/** * @param ResourceLoaderContext $context * @return array */ protected function getConfig($context) { $hash = $context->getHash(); if (isset($this->configVars[$hash])) { return $this->configVars[$hash]; } global $wgLoadScript, $wgScript, $wgStylePath, $wgScriptExtension, $wgArticlePath, $wgScriptPath, $wgServer, $wgContLang, $wgVariantArticlePath, $wgActionPaths, $wgVersion, $wgEnableAPI, $wgEnableWriteAPI, $wgDBname, $wgSitename, $wgFileExtensions, $wgExtensionAssetsPath, $wgCookiePrefix, $wgResourceLoaderMaxQueryLength, $wgResourceLoaderStorageEnabled, $wgResourceLoaderStorageVersion, $wgSearchType; $mainPage = Title::newMainPage(); /** * Namespace related preparation * - wgNamespaceIds: Key-value pairs of all localized, canonical and aliases for namespaces. * - wgCaseSensitiveNamespaces: Array of namespaces that are case-sensitive. */ $namespaceIds = $wgContLang->getNamespaceIds(); $caseSensitiveNamespaces = array(); foreach (MWNamespace::getCanonicalNamespaces() as $index => $name) { $namespaceIds[$wgContLang->lc($name)] = $index; if (!MWNamespace::isCapitalized($index)) { $caseSensitiveNamespaces[] = $index; } } // Build list of variables $vars = array('wgLoadScript' => $wgLoadScript, 'debug' => $context->getDebug(), 'skin' => $context->getSkin(), 'stylepath' => $wgStylePath, 'wgUrlProtocols' => wfUrlProtocols(), 'wgArticlePath' => $wgArticlePath, 'wgScriptPath' => $wgScriptPath, 'wgScriptExtension' => $wgScriptExtension, 'wgScript' => $wgScript, 'wgSearchType' => $wgSearchType, 'wgVariantArticlePath' => $wgVariantArticlePath, 'wgActionPaths' => (object) $wgActionPaths, 'wgServer' => $wgServer, 'wgUserLanguage' => $context->getLanguage(), 'wgContentLanguage' => $wgContLang->getCode(), 'wgVersion' => $wgVersion, 'wgEnableAPI' => $wgEnableAPI, 'wgEnableWriteAPI' => $wgEnableWriteAPI, 'wgMainPageTitle' => $mainPage->getPrefixedText(), 'wgFormattedNamespaces' => $wgContLang->getFormattedNamespaces(), 'wgNamespaceIds' => $namespaceIds, 'wgContentNamespaces' => MWNamespace::getContentNamespaces(), 'wgSiteName' => $wgSitename, 'wgFileExtensions' => array_values(array_unique($wgFileExtensions)), 'wgDBname' => $wgDBname, 'wgFileCanRotate' => BitmapHandler::canRotate(), 'wgAvailableSkins' => Skin::getSkinNames(), 'wgExtensionAssetsPath' => $wgExtensionAssetsPath, 'wgCookiePrefix' => $wgCookiePrefix, 'wgResourceLoaderMaxQueryLength' => $wgResourceLoaderMaxQueryLength, 'wgCaseSensitiveNamespaces' => $caseSensitiveNamespaces, 'wgLegalTitleChars' => Title::convertByteClassToUnicodeClass(Title::legalChars()), 'wgResourceLoaderStorageVersion' => $wgResourceLoaderStorageVersion, 'wgResourceLoaderStorageEnabled' => $wgResourceLoaderStorageEnabled); wfRunHooks('ResourceLoaderGetConfigVars', array(&$vars)); $this->configVars[$hash] = $vars; return $this->configVars[$hash]; }
public function readFromVariable( $data ) { # Authors first $matches = array(); preg_match_all( '/^ \* @author\s+(.+)$/m', $data, $matches ); $authors = $matches[1]; # Then messages $matches = array(); $regex = '/^\$(.*?)\s*=\s*[\'"](.*?)[\'"];.*?$/mus'; preg_match_all( $regex, $data, $matches, PREG_SET_ORDER ); $messages = array(); foreach ( $matches as $_ ) { $legal = Title::legalChars(); $key = preg_replace( "/([^$legal]|\\\\)/ue", '\'\x\'.' . "dechex(ord('\\0'))", $_[1] ); $value = str_replace( array( "\'", "\\\\" ), array( "'", "\\" ), $_[2] ); $messages[$key] = $value; } $messages = $this->group->getMangler()->mangle( $messages ); return array( 'AUTHORS' => $authors, 'MESSAGES' => $messages, ); }
/** * @param ResourceLoaderContext $context * @return array */ protected function getConfigSettings($context) { $hash = $context->getHash(); if (isset($this->configVars[$hash])) { return $this->configVars[$hash]; } global $wgContLang; $mainPage = Title::newMainPage(); /** * Namespace related preparation * - wgNamespaceIds: Key-value pairs of all localized, canonical and aliases for namespaces. * - wgCaseSensitiveNamespaces: Array of namespaces that are case-sensitive. */ $namespaceIds = $wgContLang->getNamespaceIds(); $caseSensitiveNamespaces = array(); foreach (MWNamespace::getCanonicalNamespaces() as $index => $name) { $namespaceIds[$wgContLang->lc($name)] = $index; if (!MWNamespace::isCapitalized($index)) { $caseSensitiveNamespaces[] = $index; } } $conf = $this->getConfig(); // Build list of variables $vars = array('wgLoadScript' => wfScript('load'), 'debug' => $context->getDebug(), 'skin' => $context->getSkin(), 'stylepath' => $conf->get('StylePath'), 'wgUrlProtocols' => wfUrlProtocols(), 'wgArticlePath' => $conf->get('ArticlePath'), 'wgScriptPath' => $conf->get('ScriptPath'), 'wgScriptExtension' => '.php', 'wgScript' => wfScript(), 'wgSearchType' => $conf->get('SearchType'), 'wgVariantArticlePath' => $conf->get('VariantArticlePath'), 'wgActionPaths' => (object) $conf->get('ActionPaths'), 'wgServer' => $conf->get('Server'), 'wgServerName' => $conf->get('ServerName'), 'wgUserLanguage' => $context->getLanguage(), 'wgContentLanguage' => $wgContLang->getCode(), 'wgTranslateNumerals' => $conf->get('TranslateNumerals'), 'wgVersion' => $conf->get('Version'), 'wgEnableAPI' => $conf->get('EnableAPI'), 'wgEnableWriteAPI' => $conf->get('EnableWriteAPI'), 'wgMainPageTitle' => $mainPage->getPrefixedText(), 'wgFormattedNamespaces' => $wgContLang->getFormattedNamespaces(), 'wgNamespaceIds' => $namespaceIds, 'wgContentNamespaces' => MWNamespace::getContentNamespaces(), 'wgSiteName' => $conf->get('Sitename'), 'wgDBname' => $conf->get('DBname'), 'wgExtraSignatureNamespaces' => $conf->get('ExtraSignatureNamespaces'), 'wgAvailableSkins' => Skin::getSkinNames(), 'wgExtensionAssetsPath' => $conf->get('ExtensionAssetsPath'), 'wgCookiePrefix' => $conf->get('CookiePrefix'), 'wgCookieDomain' => $conf->get('CookieDomain'), 'wgCookiePath' => $conf->get('CookiePath'), 'wgCookieExpiration' => $conf->get('CookieExpiration'), 'wgResourceLoaderMaxQueryLength' => $conf->get('ResourceLoaderMaxQueryLength'), 'wgCaseSensitiveNamespaces' => $caseSensitiveNamespaces, 'wgLegalTitleChars' => Title::convertByteClassToUnicodeClass(Title::legalChars()), 'wgResourceLoaderStorageVersion' => $conf->get('ResourceLoaderStorageVersion'), 'wgResourceLoaderStorageEnabled' => $conf->get('ResourceLoaderStorageEnabled'), 'wgResourceLoaderLegacyModules' => self::getLegacyModules(), 'wgForeignUploadTargets' => $conf->get('ForeignUploadTargets'), 'wgEnableUploads' => $conf->get('EnableUploads')); Hooks::run('ResourceLoaderGetConfigVars', array(&$vars)); $this->configVars[$hash] = $vars; return $this->configVars[$hash]; }
/** * Parse title and return article metadata * @param string $title * @return array article metadata (type, namespace, page_title, product, manual, topic, base_version) */ public static function getArticleMetadataFromTitle($title) { $meta = array(); if (preg_match('/^' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':(([' . PONYDOCS_PRODUCT_LEGALCHARS . ']*):([' . PONYDOCS_PRODUCTMANUAL_LEGALCHARS . ']*):([' . Title::legalChars() . ']*):([' . PONYDOCS_PRODUCTVERSION_LEGALCHARS . ']*))/i', $title, $match)) { // matched topic regex $meta['type'] = self::ARTICLE_TYPE_TOPIC; $meta['namespace'] = PONYDOCS_DOCUMENTATION_NAMESPACE_NAME; $meta['title'] = $title; $meta['page_title'] = $match[1]; $meta['product'] = $match[2]; $meta['manual'] = $match[3]; $meta['topic'] = $match[4]; $meta['base_version'] = $match[5]; } elseif (preg_match('/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':(([' . PONYDOCS_PRODUCT_LEGALCHARS . ']*):([' . PONYDOCS_PRODUCTMANUAL_LEGALCHARS . ']*)TOC([' . PONYDOCS_PRODUCTVERSION_LEGALCHARS . ']*))/i', $title, $match)) { // matched TOC regex $meta['type'] = self::ARTICLE_TYPE_TOC; $meta['namespace'] = PONYDOCS_DOCUMENTATION_NAMESPACE_NAME; $meta['title'] = $title; $meta['page_title'] = $match[1]; $meta['product'] = $match[2]; $meta['manual'] = $match[3]; $meta['base_version'] = $match[4]; } else { // no match $meta['type'] = self::ARTICLE_TYPE_OTHER; } return $meta; }
public function parseNext( $text, WikiObjectModelCollection $parentObj, $offset = 0 ) { $text = substr( $text, $offset ); $r = preg_match( '/^(\{\{\{([^{|}]+))([|}])/', $text, $m ); if ( $r ) { if ( !preg_match( '/[^' . Title::legalChars() . ']/', trim( $m[2] ) ) ) // if(!preg_match(Title::getTitleInvalidRegex(), trim($m[2]))) return array( 'len' => ( $m[3] == '|' ) ? strlen( $m[0] ) : strlen( $m[1] ), 'obj' => new WOMTemplateFieldHolderModel( trim( $m[2] ) ) ); } return null; }
function testLegalChars() { $titlechars = Title::legalChars(); foreach (range(1, 255) as $num) { $chr = chr($num); if (strpos("#[]{}<>|", $chr) !== false || preg_match("/[\\x00-\\x1f\\x7f]/", $chr)) { $this->assertFalse((bool) preg_match("/[{$titlechars}]/", $chr), "chr({$num}) = {$chr} is not a valid titlechar"); } else { $this->assertTrue((bool) preg_match("/[{$titlechars}]/", $chr), "chr({$num}) = {$chr} is a valid titlechar"); } } }
/** * Checks if the translation uses links that are discouraged. Valid links are * those that link to Special: or {{ns:special}}: or project pages trough * MediaWiki messages like {{MediaWiki:helppage-url}}:. Also links in the * definition are allowed. * * @param $messages \array Iterable list of TMessage objects. * @param $code \string Language code of the translations. * @param $warnings \array Array where warnings are appended to. */ protected function wikiLinksCheck( $messages, $code, &$warnings ) { $tc = Title::legalChars() . '#%{}'; foreach ( $messages as $message ) { $key = $message->key(); $definition = $message->definition(); $translation = $message->translation(); $subcheck = 'extra'; $matches = $links = array(); preg_match_all( "/\[\[([{$tc}]+)(\\|(.+?))?]]/sDu", $translation, $matches ); for ( $i = 0; $i < count( $matches[0] ); $i++ ) { $backMatch = preg_quote( $matches[1][$i], '/' ); if ( preg_match( "/\[\[$backMatch/", $definition ) ) { continue; } $links[] = "[[{$matches[1][$i]}{$matches[2][$i]}]]"; } if ( count( $links ) ) { $warnings[$key][] = array( array( 'links', $subcheck, $key, $code ), 'translate-checks-links', array( 'PARAMS', $links ), array( 'COUNT', count( $links ) ), ); } $subcheck = 'missing'; $matches = $links = array(); preg_match_all( "/\[\[([{$tc}]+)(\\|(.+?))?]]/sDu", $definition, $matches ); for ( $i = 0; $i < count( $matches[0] ); $i++ ) { $backMatch = preg_quote( $matches[1][$i], '/' ); if ( preg_match( "/\[\[$backMatch/", $translation ) ) { continue; } $links[] = "[[{$matches[1][$i]}{$matches[2][$i]}]]"; } if ( count( $links ) ) { $warnings[$key][] = array( array( 'links', $subcheck, $key, $code ), 'translate-checks-links-missing', array( 'PARAMS', $links ), array( 'COUNT', count( $links ) ), ); } } }
/** * Returns a simple regex that will match on characters and sequences invalid in titles. * Note that this doesn't pick up many things that could be wrong with titles, but that * replacing this regex with something valid will make many titles valid. * * @return String regex string */ static function getTitleInvalidRegex() { static $rxTc = false; if (!$rxTc) { # Matching titles will be held as illegal. $rxTc = '/' . '[^' . Title::legalChars() . ']' . '|%[0-9A-Fa-f]{2}' . '|&[A-Za-z0-9\\x80-\\xff]+;' . '|&#[0-9]+;' . '|&#x[0-9A-Fa-f]+;' . '/S'; } return $rxTc; }
/** * Secure and split - main initialisation function for this object * * Assumes that mDbkeyform has been set, and is urldecoded * and uses underscores, but not otherwise munged. This function * removes illegal characters, splits off the interwiki and * namespace prefixes, sets the other forms, and canonicalizes * everything. * @return bool true on success */ private function secureAndSplit() { global $wgContLang, $wgLocalInterwiki, $wgCapitalLinks; # Initialisation static $rxTc = false; if (!$rxTc) { # Matching titles will be held as illegal. $rxTc = '/' . '[^' . Title::legalChars() . ']' . '|%[0-9A-Fa-f]{2}' . '|&[A-Za-z0-9\\x80-\\xff]+;' . '|&#[0-9]+;' . '|&#x[0-9A-Fa-f]+;' . '/S'; } $this->mInterwiki = $this->mFragment = ''; $this->mNamespace = $this->mDefaultNamespace; # Usually NS_MAIN $dbkey = $this->mDbkeyform; # Strip Unicode bidi override characters. # Sometimes they slip into cut-n-pasted page titles, where the # override chars get included in list displays. $dbkey = str_replace("", '', $dbkey); // 200E LEFT-TO-RIGHT MARK $dbkey = str_replace("", '', $dbkey); // 200F RIGHT-TO-LEFT MARK # Clean up whitespace # // XXCHANGED don't replace _ with - screws up namespaces $dbkey = preg_replace('/[ ]+/', '-', $this->mDbkeyform); $dbkey = trim($dbkey, '-'); if ('' == $dbkey) { return false; } if (false !== strpos($dbkey, UTF8_REPLACEMENT)) { # Contained illegal UTF-8 sequences or forbidden Unicode chars. return false; } $this->mDbkeyform = $dbkey; # Initial colon indicates main namespace rather than specified default # but should not create invalid {ns,title} pairs such as {0,Project:Foo} if (':' == $dbkey[0]) { $this->mNamespace = NS_MAIN; $dbkey = substr($dbkey, 1); # remove the colon but continue processing $dbkey = trim($dbkey, '-'); # remove any subsequent whitespace } # Namespace or interwiki prefix $firstPass = true; do { $m = array(); if (preg_match("/^(.+?)_*:_*(.*)\$/S", $dbkey, $m)) { $p = $m[1]; if ($ns = $wgContLang->getNsIndex($p)) { # Ordinary namespace $dbkey = $m[2]; $this->mNamespace = $ns; } elseif ($this->getInterwikiLink($p)) { if (!$firstPass) { # Can't make a local interwiki link to an interwiki link. # That's just crazy! return false; } # Interwiki link $dbkey = $m[2]; $this->mInterwiki = $wgContLang->lc($p); # Redundant interwiki prefix to the local wiki if (0 == strcasecmp($this->mInterwiki, $wgLocalInterwiki)) { if ($dbkey == '') { # Can't have an empty self-link return false; } $this->mInterwiki = ''; $firstPass = false; # Do another namespace split... continue; } # If there's an initial colon after the interwiki, that also # resets the default namespace if ($dbkey !== '' && $dbkey[0] == ':') { $this->mNamespace = NS_MAIN; $dbkey = substr($dbkey, 1); } } # If there's no recognized interwiki or namespace, # then let the colon expression be part of the title. } break; } while (true); # We already know that some pages won't be in the database! # if ('' != $this->mInterwiki || NS_SPECIAL == $this->mNamespace) { $this->mArticleID = 0; } $fragment = strstr($dbkey, '#'); if (false !== $fragment) { $this->setFragment($fragment); $dbkey = substr($dbkey, 0, strlen($dbkey) - strlen($fragment)); # remove whitespace again: prevents "Foo_bar_#" # becoming "Foo_bar_" $dbkey = preg_replace('/_*$/', '', $dbkey); } # Reject illegal characters. # if (preg_match($rxTc, $dbkey)) { return false; } /** * Pages with "/./" or "/../" appearing in the URLs will * often be unreachable due to the way web browsers deal * with 'relative' URLs. Forbid them explicitly. */ if (strpos($dbkey, '.') !== false && ($dbkey === '.' || $dbkey === '..' || strpos($dbkey, './') === 0 || strpos($dbkey, '../') === 0 || strpos($dbkey, '/./') !== false || strpos($dbkey, '/../') !== false || substr($dbkey, -2) == '/.' || substr($dbkey, -3) == '/..')) { return false; } /** * Magic tilde sequences? Nu-uh! */ if (strpos($dbkey, '~~~') !== false) { return false; } /** * Limit the size of titles to 255 bytes. * This is typically the size of the underlying database field. * We make an exception for special pages, which don't need to be stored * in the database, and may edge over 255 bytes due to subpage syntax * for long titles, e.g. [[Special:Block/Long name]] */ if ($this->mNamespace != NS_SPECIAL && strlen($dbkey) > 255 || strlen($dbkey) > 512) { return false; } /** * Normally, all wiki links are forced to have * an initial capital letter so [[foo]] and [[Foo]] * point to the same place. * * Don't force it for interwikis, since the other * site might be case-sensitive. */ $this->mUserCaseDBKey = $dbkey; // INTL: By default, capitalize first letter of titles with namespace of NS_MEDIAWIKI. A little bit of a hack // to get around the fact that we set wgCapitalLinks to false to international sites. We do this because not all // languages capitalize the first letter of a title if ($this->mNamespace == NS_MEDIAWIKI || $wgCapitalLinks && $this->mInterwiki == '') { $dbkey = $wgContLang->ucfirst($dbkey); } /** * Can't make a link to a namespace alone... * "empty" local links can only be self-links * with a fragment identifier. */ if ($dbkey == '' && $this->mInterwiki == '' && $this->mNamespace != NS_MAIN) { return false; } // Allow IPv6 usernames to start with '::' by canonicalizing IPv6 titles. // IP names are not allowed for accounts, and can only be referring to // edits from the IP. Given '::' abbreviations and caps/lowercaps, // there are numerous ways to present the same IP. Having sp:contribs scan // them all is silly and having some show the edits and others not is // inconsistent. Same for talk/userpages. Keep them normalized instead. $dbkey = $this->mNamespace == NS_USER || $this->mNamespace == NS_USER_TALK ? IP::sanitizeIP($dbkey) : $dbkey; // Any remaining initial :s are illegal. if ($dbkey !== '' && ':' == $dbkey[0]) { return false; } # Fill fields $this->mDbkeyform = $dbkey; $this->mUrlform = wfUrlencode($dbkey); //XXCHANGED $this->mTextform = str_replace('-', ' ', $dbkey); return true; }
function wfIFI_handleUpload($f, $import) { global $wgRequest, $wgUser, $wgOut, $wgTmpDirectory; global $wgIFI_GetOriginal, $wgIFI_CreditsTemplate, $wgIFI_AppendRandomNumber; # Check token, to preven Cross Site Request Forgeries $token = $wgRequest->getVal('token'); if (!$wgUser->matchEditToken($token)) { $wgOut->addWikitext(wfMsg('sessionfailure')); return false; } $id = $wgRequest->getVal('id'); $ititle = $wgRequest->getVal('ititle'); $owner = $wgRequest->getVal('owner'); $name = $wgRequest->getVal('name'); if ($wgIFI_GetOriginal) { // get URL of original :1 $sizes = $f->photos_getSizes($id); $original = ''; foreach ($sizes as $size) { if ($size['label'] == 'Original') { $original = $size['source']; $import = $size['source']; } else { if ($size['label'] == 'Large') { $large = $size['source']; } } } //somtimes Large is returned but no Original! if ($original == '' && $large != '') { $import = $large; } } if (!preg_match('/^http:\\/\\/farm[0-9]+\\.static\\.flickr\\.com\\/.*\\.(jpg|gif|png)$/', $import, $matches)) { $wgOut->showErrorPage('error', 'importfreeimages_invalidurl', array(wfEscapeWikiText($import))); return true; } $fileext = '.' . $matches[1]; // store the contents of the file $pageContents = file_get_contents($import); $tempname = tempnam($wgTmpDirectory, 'flickr'); $r = fopen($tempname, 'wb'); if ($r === FALSE) { # Could not open temporary file to write in $wgOut->errorPage('upload-file-error', 'upload-file-error-text'); return true; } $size = fwrite($r, $pageContents); fclose($r); $info = $f->photos_getInfo($id); $name_wiki = wfEscapeWikiText($name); if (!empty($wgIFI_CreditsTemplate)) { $owner_wiki = wfEscapeWikiText($owner); $id_wiki = wfEscapeWikiText($id); $caption = "{{" . $wgIFI_CreditsTemplate . intval($info['license']) . "|1={$id_wiki}|2={$owner_wiki}|3={$name_wiki}}}"; } else { // TODO: this is totally wrong: The whole message should be configurable, we shouldn't include arbitrary templates // additionally, the license information is not correct (we are not guaranteed to get "CC by 2.0" images only) $caption = wfMsgForContent('importfreeimages_filefromflickr', $ititle, "http://www.flickr.com/people/" . urlencode($owner) . " " . $name_wiki) . " <nowiki>{$import}</nowiki>. {{CC by 2.0}} "; $caption = trim($caption); } if (!class_exists("UploadForm")) { require_once 'includes/SpecialUpload.php'; } $u = new UploadForm($wgRequest); // TODO: we should use FauxRequest here instead of accessing member variables. // But FauxRequest doesn't yet allow us to pass files around $u->mTempPath = $tempname; $u->mFileSize = $size; $u->mComment = $caption; $u->mRemoveTempFile = true; $u->mIgnoreWarning = true; $filename = $ititle . ($wgIFI_AppendRandomNumber ? "-" . rand(0, 9999) : "") . $fileext; $filename = preg_replace('/ +/', ' ', $filename); /** * Filter out illegal characters, and try to make a legible name * out of it. We'll strip some silently that Title would die on. * This is taken from SpecialUpload::internalProcessUploads() */ $filename = preg_replace("/[^" . Title::legalChars() . "]|:/", '-', $filename); $nt = Title::makeTitleSafe(NS_IMAGE, $filename); if (is_null($nt)) { $wgOut->showErrorPage('error', 'illegalfilename', array(wfEscapeWikiText($filename))); return false; } $u->mSrcName = $filename; if ($nt->getArticleID() > 0) { $sk = $wgUser->getSkin(); $dlink = $sk->makeKnownLinkObj($t); $warning = '<li>' . wfMsgExt('fileexists', '', $dlink) . '</li>'; // use our own upload warning as we dont have a 'reupload' feature wfIFI_uploadWarning($u, $warning); return true; } elseif (!$nt->userCan('create')) { $wgOut->showPermissionsErrorPage($nt->getUserPermissionsErrors('create', $wgUser)); return false; } else { $u->execute(); return true; } }
/** * Replace all invalid characters with '-'. * Additional characters can be defined in $wgIllegalFileChars (see T22489). * By default, $wgIllegalFileChars includes ':', '/', '\'. * * @param string $name Filename to process * @return string */ function wfStripIllegalFilenameChars($name) { global $wgIllegalFileChars; $illegalFileChars = $wgIllegalFileChars ? "|[" . $wgIllegalFileChars . "]" : ''; $name = preg_replace("/[^" . Title::legalChars() . "]" . $illegalFileChars . "/", '-', $name); // $wgIllegalFileChars may not include '/' and '\', so we still need to do this $name = wfBaseName($name); return $name; }
/** * Really do the upload * Checks are made in SpecialUpload::execute() * @access private */ function processUpload() { global $wgUser, $wgOut, $wgLang, $wgContLang; global $wgUploadDirectory; global $wgUseCopyrightUpload, $wgCheckCopyrightUpload; /** * If there was no filename or a zero size given, give up quick. */ if (trim($this->mOname) == '' || empty($this->mUploadSize)) { return $this->mainUploadForm('<li>' . wfMsg('emptyfile') . '</li>'); } # Chop off any directories in the given filename if ($this->mDestFile) { $basename = basename($this->mDestFile); } else { $basename = basename($this->mOname); } /** * We'll want to blacklist against *any* 'extension', and use * only the final one for the whitelist. */ list($partname, $ext) = $this->splitExtensions($basename); if (count($ext)) { $finalExt = $ext[count($ext) - 1]; } else { $finalExt = ''; } $fullExt = implode('.', $ext); if (strlen($partname) < 3) { $this->mainUploadForm(wfMsg('minlength')); return; } /** * Filter out illegal characters, and try to make a legible name * out of it. We'll strip some silently that Title would die on. */ $filtered = preg_replace("/[^" . Title::legalChars() . "]|:/", '-', $basename); $nt = Title::newFromText($filtered); if (is_null($nt)) { return $this->uploadError(wfMsg('illegalfilename', htmlspecialchars($filtered))); } $nt =& Title::makeTitle(NS_IMAGE, $nt->getDBkey()); $this->mUploadSaveName = $nt->getDBkey(); /** * If the image is protected, non-sysop users won't be able * to modify it by uploading a new revision. */ if (!$nt->userCanEdit()) { return $this->uploadError(wfMsg('protectedpage')); } /* Don't allow users to override the blacklist (check file extension) */ global $wgStrictFileExtensions; global $wgFileExtensions, $wgFileBlacklist; if ($this->checkFileExtensionList($ext, $wgFileBlacklist) || $wgStrictFileExtensions && !$this->checkFileExtension($finalExt, $wgFileExtensions)) { return $this->uploadError(wfMsg('badfiletype', htmlspecialchars($fullExt))); } /** * Look at the contents of the file; if we can recognize the * type but it's corrupt or data of the wrong type, we should * probably not accept it. */ if (!$this->mStashed) { $veri = $this->verify($this->mUploadTempName, $finalExt); if ($veri !== true) { //it's a wiki error... return $this->uploadError($veri->toString()); } } /** * Check for non-fatal conditions */ if (!$this->mIgnoreWarning) { $warning = ''; if ($this->mUploadSaveName != ucfirst($filtered)) { $warning .= '<li>' . wfMsg('badfilename', htmlspecialchars($this->mUploadSaveName)) . '</li>'; } global $wgCheckFileExtensions; if ($wgCheckFileExtensions) { if (!$this->checkFileExtension($finalExt, $wgFileExtensions)) { $warning .= '<li>' . wfMsg('badfiletype', htmlspecialchars($fullExt)) . '</li>'; } } global $wgUploadSizeWarning; if ($wgUploadSizeWarning && $this->mUploadSize > $wgUploadSizeWarning) { # TODO: Format $wgUploadSizeWarning to something that looks better than the raw byte # value, perhaps add GB,MB and KB suffixes? $warning .= '<li>' . wfMsg('largefile', $wgUploadSizeWarning, $this->mUploadSize) . '</li>'; } if ($this->mUploadSize == 0) { $warning .= '<li>' . wfMsg('emptyfile') . '</li>'; } if ($nt->getArticleID()) { global $wgUser; $sk = $wgUser->getSkin(); $dlink = $sk->makeKnownLinkObj($nt); $warning .= '<li>' . wfMsg('fileexists', $dlink) . '</li>'; } if ($warning != '') { /** * Stash the file in a temporary location; the user can choose * to let it through and we'll complete the upload then. */ return $this->uploadWarning($warning); } } /** * Try actually saving the thing... * It will show an error form on failure. */ if ($this->saveUploadedFile($this->mUploadSaveName, $this->mUploadTempName, !empty($this->mSessionKey))) { /** * Update the upload log and create the description page * if it's a new file. */ $img = Image::newFromName($this->mUploadSaveName); $success = $img->recordUpload($this->mUploadOldVersion, $this->mUploadDescription, $this->mUploadCopyStatus, $this->mUploadSource); if ($success) { $this->showSuccess(); } else { // Image::recordUpload() fails if the image went missing, which is // unlikely, hence the lack of a specialised message $wgOut->fileNotFoundError($this->mUploadSaveName); } } }
/** I BORROWED THIS FUNCTION FROM SpecialUpload.php!! CHECK FOR EACH VERSION OF MEDIAWIKI, IF * THIS FUNCTION STILL MAKES SENSE! * */ function processUpload() { global $wgUser, $wgUploadDirectory, $wgRequest; $fname = "AnyWikiDraw_body::processUpload"; // Retrieve form fields $drawingName = $wgRequest->getText('DrawingName'); $drawingWidth = $wgRequest->getText('DrawingWidth'); $drawingHeight = $wgRequest->getText('DrawingHeight'); $drawingTempFile = $wgRequest->getFileTempName('DrawingData'); $drawingFileSize = $wgRequest->getFileSize('DrawingData'); $drawingUploadError = $wgRequest->getUploadError('DrawingData'); $renderedTempFile = $wgRequest->getFileTempName('RenderedImageData'); $renderedFileSize = $wgRequest->getFileSize('RenderedImageData'); $renderedUploadError = $wgRequest->getUploadError('RenderedImageData'); $imageMapTempFile = $wgRequest->getFileTempName('ImageMapData'); $imageMapFileSize = $wgRequest->getFileSize('ImageMapData'); $imageMapUploadError = $wgRequest->getUploadError('ImageMapData'); $uploadSummary = $wgRequest->getText('UploadSummary'); // validate image dimension if (!is_numeric($drawingWidth) || $drawingWidth < 1) { $drawingWidth = null; } if (!is_numeric($drawingHeight) || $drawingHeight < 1) { $drawingHeight = null; } # If there was no filename or no image data, give up quickly. if (strlen($drawingName) == 0 || $drawingFileSize == 0) { wfDebug('[client ' . $_SERVER["REMOTE_ADDR"] . ']' . '[user ' . $wgUser->getName() . '] ' . $fname . ' received bad request [DrawingName=' . $drawingName . ']' . '[fileSize(DrawingData)=' . $drawingFileSize . ']'); header('HTTP/1.0 400 Bad Request'); exit("\n\n" + '<html><body>DrawingName and DrawingData must be supplied.</body></html>'); } // Verify filename # Chop off any directories in the given filename. $drawingName = wfBaseName($drawingName); $imageExtension = substr(strrchr($drawingName, '.'), 1); # Only allow filenames with known extensions $allowedExtensions = array('svg', 'svgz', 'png', 'jpg'); if (!in_array($imageExtension, $allowedExtensions)) { wfDebug('[client ' . $_SERVER["REMOTE_ADDR"] . ']' . '[user ' . $wgUser->getName() . '] ' . $fname . ' Received bad image extension [DrawingName=' . $drawingName . ']'); header('HTTP/1.0 400 Bad Request'); exit("\n\n" + '<html><body>DrawingName must have one of the following extensions: ' . implode(',', $allowedExtensions) . '.</body></html>'); } /** * Filter out illegal characters, and try to make a legible name * out of it. We'll strip some silently that Title would die on. */ $filtered = preg_replace("/[^" . Title::legalChars() . "]|:/", '-', $drawingName); $nt = Title::newFromText($filtered); if (is_null($nt)) { wfDebug('[client ' . $_SERVER["REMOTE_ADDR"] . ']' . '[user ' . $wgUser->getName() . '] ' . $fname . ' Received bad image name [DrawingName=' . $drawingName . ']'); header('HTTP/1.0 400 Bad Request'); exit("\n\n" + '<html><body>DrawingName must contain legible characters only.</body></html>'); } $nt =& Title::makeTitle(NS_IMAGE, $nt->getDBkey()); $uploadSaveName = $nt->getDBkey(); /** * If the image is protected, non-sysop users won't be able * to modify it by uploading a new revision. */ if (!$nt->userCanEdit()) { wfDebug('[client ' . $_SERVER["REMOTE_ADDR"] . ']' . '[user ' . $wgUser->getName() . '] ' . $fname . ' image is protected [DrawingName=' . $drawingName . ']'); header('HTTP/1.0 403 Forbidden'); exit("\n\n" + '<html><body>You are not allowed to edit this image.</body></html>'); } /** * In some cases we may forbid overwriting of existing files. */ if (!$this->userCanOverwrite($uploadSaveName)) { wfDebug('[client ' . $_SERVER["REMOTE_ADDR"] . ']' . '[user ' . $wgUser->getName() . '] ' . $fname . ' image may not be overwritten [DrawingName=' . $drawingName . ']'); header('HTTP/1.0 403 Forbidden'); exit("\n\n" + '<html><body>You are not allowed to overwrite this image.</body></html>'); } /** Check if the image directory is writeable, this is a common mistake */ if (!is_writeable($wgUploadDirectory)) { header('HTTP/1.0 403 Forbidden'); exit("\n\n" + '<html><body>The upload directory on the server is read only.</body></html>'); } /** * Upload the file into the temp directory, so that we can scrutinize its content */ $archive = wfImageArchiveDir($uploadSaveName, 'temp'); /** * Look at the contents of the file; if we can recognize the * type but it's corrupt or data of the wrong type, we should * probably not accept it. */ $veri = $this->verify($drawingTempFile, $imageExtension); if ($veri !== true) { wfDebug('[client ' . $_SERVER["REMOTE_ADDR"] . ']' . '[user ' . $wgUser->getName() . '] ' . $fname . ' image failed verification [DrawingName=' . $drawingName . '][DrawingTempFile=' . $drawingTempFile . ']'); unlink($drawingTempFile); header('HTTP/1.0 400 Bad Request'); exit("\n\n" + '<html><body>The image data is corrupt.</body></html>'); } /** * Provide an opportunity for extensions to add further checks */ $error = ''; if (!wfRunHooks('UploadVerification', array($uploadSaveName, $drawingTempFile, &$error))) { wfDebug('[client ' . $_SERVER["REMOTE_ADDR"] . ']' . '[user ' . $wgUser->getName() . '] ' . $fname . ' image failed extended verification [DrawingName=' . $drawingName . ']'); unlink($drawingTempFile); header('HTTP/1.0 400 Bad Request'); exit("\n\n" + '<html><body>The image data does not match the image name extension.</body></html>'); } /** * Try actually saving the thing... * It will show an error form on failure. */ if ($this->saveUploadedFile($uploadSaveName, $drawingTempFile, true)) { /** * Update the upload log and create the description page * if it's a new file. */ $img = Image::newFromName($uploadSaveName); if ($drawingWidth != null) { $img->width = $drawingWidth; } if ($drawingHeight != null) { $img->height = $drawingHeight; } $this->mUploadDescription = $uploadSummary; $success = $img->recordUpload($this->mUploadOldVersion, $this->mUploadDescription, $this->mLicense, $this->mUploadCopyStatus, $this->mUploadSource, $this->mWatchthis); /** * Save the rendered image, if one was provided */ if ($renderedTempFile != null && $drawingWidth != null) { $thumbName = $img->thumbName($drawingWidth, $img->fromSharedDirectory); $thumbDir = wfImageThumbDir($img->name, $img->fromSharedDirectory); $thumbPath = $thumbDir . '/' . $thumbName; wfDebug("we have a rendered image: " . $renderedTempFile . ' width=' . $drawingWidth . ' height=' . $drawingHeight . ' thumbName=' . $thumbPath); if (!file_exists(dirname($thumbPath))) { mkdir(dirname($thumbPath), 0777, true); } // Look at the contents of the file; if we can recognize the // type but it's corrupt or data of the wrong type, we should // probably not accept it. $veri = $this->verify($renderedTempFile, 'png'); if ($veri !== true) { wfDebug('[client ' . $_SERVER["REMOTE_ADDR"] . ']' . '[user ' . $wgUser->getName() . '] ' . $fname . ' rendered image failed verification [DrawingName=' . $drawingName . '][RenderedTempFile=' . $renderedTempFile . ']'); unlink($renderedTempFile); } else { move_uploaded_file($renderedTempFile, $thumbPath); } } else { if ($renderedTempFile != null) { unlink($renderedTempFile); } } /** * Save the image map, if one was provided */ if ($imageMapTempFile != null && $drawingWidth != null) { $thumbName = $img->thumbName($drawingWidth, $img->fromSharedDirectory); $thumbDir = wfImageThumbDir($img->name, $img->fromSharedDirectory); $imageMapPath = $thumbDir . '/' . $thumbName . '.map'; wfDebug("we have an image map: " . $imageMapTempFile); if (!file_exists(dirname($imageMapPath))) { mkdir(dirname($imageMapPath), 0777, true); } // Look at the contents of the file; if we can recognize the // type but it's corrupt or data of the wrong type, we should // probably not accept it. $hasScript = $this->detectScript($imageMapTempFile, 'text/html', 'html'); if ($hasScript !== false) { wfDebug('[client ' . $_SERVER["REMOTE_ADDR"] . ']' . '[user ' . $wgUser->getName() . '] ' . $fname . ' image map failed verification [DrawingName=' . $drawingName . '][ImageMapTempFile=' . $imageMapTempFile . ']'); unlink($imageMapTempFile); } else { move_uploaded_file($imageMapTempFile, $imageMapPath); } } else { if ($imageMapTempFile != null) { unlink($imageMapTempFile); } } if ($success) { $this->showSuccess(); wfRunHooks('UploadComplete', array(&$img)); } else { // Image::recordUpload() fails if the image went missing, which is // unlikely, hence the lack of a specialised message $wgOut->showFileNotFoundError($this->mUploadSaveName); } } if ($renderedTempFile != null) { unlink($renderedTempFile); } if ($imageMapTempFile != null) { unlink($imageMapTempFile); } }
/** * Process [[ ]] wikilinks (RIL) * @return LinkHolderArray * * @private */ function replaceInternalLinks2(&$s) { global $wgContLang; wfProfileIn(__METHOD__); wfProfileIn(__METHOD__ . '-setup'); static $tc = FALSE, $e1, $e1_img; # the % is needed to support urlencoded titles as well if (!$tc) { $tc = Title::legalChars() . '#%'; # Match a link having the form [[namespace:link|alternate]]trail $e1 = "/^([{$tc}]+)(?:\\|(.+?))?]](.*)\$/sD"; # Match cases where there is no "]]", which might still be images $e1_img = "/^([{$tc}]+)\\|(.*)\$/sD"; } $sk = $this->mOptions->getSkin(); $holders = new LinkHolderArray($this); #split the entire text string on occurences of [[ $a = StringUtils::explode('[[', ' ' . $s); #get the first element (all text up to first [[), and remove the space we added $s = $a->current(); $a->next(); $line = $a->current(); # Workaround for broken ArrayIterator::next() that returns "void" $s = substr($s, 1); $useLinkPrefixExtension = $wgContLang->linkPrefixExtension(); $e2 = null; if ($useLinkPrefixExtension) { # Match the end of a line for a word that's not followed by whitespace, # e.g. in the case of 'The Arab al[[Razi]]', 'al' will be matched $e2 = wfMsgForContent('linkprefix'); } if (is_null($this->mTitle)) { wfProfileOut(__METHOD__ . '-setup'); wfProfileOut(__METHOD__); throw new MWException(__METHOD__ . ": \$this->mTitle is null\n"); } $nottalk = !$this->mTitle->isTalkPage(); if ($useLinkPrefixExtension) { $m = array(); if (preg_match($e2, $s, $m)) { $first_prefix = $m[2]; } else { $first_prefix = false; } } else { $prefix = ''; } if ($wgContLang->hasVariants()) { $selflink = $wgContLang->convertLinkToAllVariants($this->mTitle->getPrefixedText()); } else { $selflink = array($this->mTitle->getPrefixedText()); } $useSubpages = $this->areSubpagesAllowed(); wfProfileOut(__METHOD__ . '-setup'); # Loop for each link for (; $line !== false && $line !== null; $a->next(), $line = $a->current()) { # Check for excessive memory usage if ($holders->isBig()) { # Too big # Do the existence check, replace the link holders and clear the array $holders->replace($s); $holders->clear(); } if ($useLinkPrefixExtension) { wfProfileIn(__METHOD__ . '-prefixhandling'); if (preg_match($e2, $s, $m)) { $prefix = $m[2]; $s = $m[1]; } else { $prefix = ''; } # first link if ($first_prefix) { $prefix = $first_prefix; $first_prefix = false; } wfProfileOut(__METHOD__ . '-prefixhandling'); } $might_be_img = false; wfProfileIn(__METHOD__ . "-e1"); if (preg_match($e1, $line, $m)) { # page with normal text or alt $text = $m[2]; # If we get a ] at the beginning of $m[3] that means we have a link that's something like: # [[Image:Foo.jpg|[http://example.com desc]]] <- having three ] in a row f***s up, # the real problem is with the $e1 regex # See bug 1300. # # Still some problems for cases where the ] is meant to be outside punctuation, # and no image is in sight. See bug 2095. # if ($text !== '' && substr($m[3], 0, 1) === ']' && strpos($text, '[') !== false) { $text .= ']'; # so that replaceExternalLinks($text) works later $m[3] = substr($m[3], 1); } # fix up urlencoded title texts if (strpos($m[1], '%') !== false) { # Should anchors '#' also be rejected? $m[1] = str_replace(array('<', '>'), array('<', '>'), urldecode($m[1])); } $trail = $m[3]; } elseif (preg_match($e1_img, $line, $m)) { # Invalid, but might be an image with a link in its caption $might_be_img = true; $text = $m[2]; if (strpos($m[1], '%') !== false) { $m[1] = urldecode($m[1]); } $trail = ""; } else { # Invalid form; output directly $s .= $prefix . '[[' . $line; wfProfileOut(__METHOD__ . "-e1"); continue; } wfProfileOut(__METHOD__ . "-e1"); wfProfileIn(__METHOD__ . "-misc"); # Don't allow internal links to pages containing # PROTO: where PROTO is a valid URL protocol; these # should be external links. if (preg_match('/^\\b(?:' . wfUrlProtocols() . ')/', $m[1])) { $s .= $prefix . '[[' . $line; wfProfileOut(__METHOD__ . "-misc"); continue; } # Make subpage if necessary if ($useSubpages) { $link = $this->maybeDoSubpageLink($m[1], $text); } else { $link = $m[1]; } $noforce = substr($m[1], 0, 1) !== ':'; if (!$noforce) { # Strip off leading ':' $link = substr($link, 1); } wfProfileOut(__METHOD__ . "-misc"); wfProfileIn(__METHOD__ . "-title"); $nt = Title::newFromText($this->mStripState->unstripNoWiki($link)); if ($nt === NULL) { $s .= $prefix . '[[' . $line; wfProfileOut(__METHOD__ . "-title"); continue; } $ns = $nt->getNamespace(); $iw = $nt->getInterWiki(); wfProfileOut(__METHOD__ . "-title"); if ($might_be_img) { # if this is actually an invalid link wfProfileIn(__METHOD__ . "-might_be_img"); if ($ns == NS_FILE && $noforce) { #but might be an image $found = false; while (true) { #look at the next 'line' to see if we can close it there $a->next(); $next_line = $a->current(); if ($next_line === false || $next_line === null) { break; } $m = explode(']]', $next_line, 3); if (count($m) == 3) { # the first ]] closes the inner link, the second the image $found = true; $text .= "[[{$m[0]}]]{$m[1]}"; $trail = $m[2]; break; } elseif (count($m) == 2) { #if there's exactly one ]] that's fine, we'll keep looking $text .= "[[{$m[0]}]]{$m[1]}"; } else { #if $next_line is invalid too, we need look no further $text .= '[[' . $next_line; break; } } if (!$found) { # we couldn't find the end of this imageLink, so output it raw #but don't ignore what might be perfectly normal links in the text we've examined $holders->merge($this->replaceInternalLinks2($text)); $s .= "{$prefix}[[{$link}|{$text}"; # note: no $trail, because without an end, there *is* no trail wfProfileOut(__METHOD__ . "-might_be_img"); continue; } } else { #it's not an image, so output it raw $s .= "{$prefix}[[{$link}|{$text}"; # note: no $trail, because without an end, there *is* no trail wfProfileOut(__METHOD__ . "-might_be_img"); continue; } wfProfileOut(__METHOD__ . "-might_be_img"); } $wasblank = '' == $text; if ($wasblank) { $text = $link; } # Link not escaped by : , create the various objects if ($noforce) { # Interwikis wfProfileIn(__METHOD__ . "-interwiki"); if ($iw && $this->mOptions->getInterwikiMagic() && $nottalk && $wgContLang->getLanguageName($iw)) { $this->mOutput->addLanguageLink($nt->getFullText()); $s = rtrim($s . $prefix); $s .= trim($trail, "\n") == '' ? '' : $prefix . $trail; wfProfileOut(__METHOD__ . "-interwiki"); continue; } wfProfileOut(__METHOD__ . "-interwiki"); if ($ns == NS_FILE) { wfProfileIn(__METHOD__ . "-image"); if (!wfIsBadImage($nt->getDBkey(), $this->mTitle)) { # recursively parse links inside the image caption # actually, this will parse them in any other parameters, too, # but it might be hard to fix that, and it doesn't matter ATM $text = $this->replaceExternalLinks($text); $holders->merge($this->replaceInternalLinks2($text)); # cloak any absolute URLs inside the image markup, so replaceExternalLinks() won't touch them $s .= $prefix . $this->armorLinks($this->makeImage($nt, $text, $holders)) . $trail; } $this->mOutput->addImage($nt->getDBkey()); wfProfileOut(__METHOD__ . "-image"); continue; } if ($ns == NS_CATEGORY) { wfProfileIn(__METHOD__ . "-category"); $s = rtrim($s . "\n"); # bug 87 if ($wasblank) { $sortkey = $this->getDefaultSort(); } else { $sortkey = $text; } $sortkey = Sanitizer::decodeCharReferences($sortkey); $sortkey = str_replace("\n", '', $sortkey); $sortkey = $wgContLang->convertCategoryKey($sortkey); $this->mOutput->addCategory($nt->getDBkey(), $sortkey); /** * Strip the whitespace Category links produce, see bug 87 * @todo We might want to use trim($tmp, "\n") here. */ $s .= trim($prefix . $trail, "\n") == '' ? '' : $prefix . $trail; wfProfileOut(__METHOD__ . "-category"); continue; } } # Self-link checking if ($nt->getFragment() === '' && $ns != NS_SPECIAL) { if (in_array($nt->getPrefixedText(), $selflink, true)) { $s .= $prefix . $sk->makeSelfLinkObj($nt, $text, '', $trail); continue; } } # NS_MEDIA is a pseudo-namespace for linking directly to a file # FIXME: Should do batch file existence checks, see comment below if ($ns == NS_MEDIA) { wfProfileIn(__METHOD__ . "-media"); # Give extensions a chance to select the file revision for us $skip = $time = false; wfRunHooks('BeforeParserMakeImageLinkObj', array(&$this, &$nt, &$skip, &$time)); if ($skip) { $link = $sk->link($nt); } else { $link = $sk->makeMediaLinkObj($nt, $text, $time); } # Cloak with NOPARSE to avoid replacement in replaceExternalLinks $s .= $prefix . $this->armorLinks($link) . $trail; $this->mOutput->addImage($nt->getDBkey()); wfProfileOut(__METHOD__ . "-media"); continue; } wfProfileIn(__METHOD__ . "-always_known"); # Some titles, such as valid special pages or files in foreign repos, should # be shown as bluelinks even though they're not included in the page table # # FIXME: isAlwaysKnown() can be expensive for file links; we should really do # batch file existence checks for NS_FILE and NS_MEDIA if ($iw == '' && $nt->isAlwaysKnown()) { $this->mOutput->addLink($nt); $s .= $this->makeKnownLinkHolder($nt, $text, '', $trail, $prefix); } else { # Links will be added to the output link list after checking $s .= $holders->makeHolder($nt, $text, '', $trail, $prefix); } wfProfileOut(__METHOD__ . "-always_known"); } wfProfileOut(__METHOD__); return $holders; }
/** * This functions handle the third step of the WMU, image insertion * * @return bool|String */ function insertImage() { global $wgRequest, $wgUser, $wgContLang; $type = $wgRequest->getVal('type'); $name = $wgRequest->getVal('name'); $mwname = $wgRequest->getVal('mwname'); $tempid = $wgRequest->getVal('tempid'); $gallery = $wgRequest->getVal('gallery', ''); $title_main = urldecode($wgRequest->getVal('article', '')); $ns = $wgRequest->getVal('ns', ''); $link = urldecode($wgRequest->getVal('link', '')); // Are we in the ck editor? $ck = $wgRequest->getVal('ck'); $extraId = $wgRequest->getVal('extraId'); $newFile = true; $file = null; if ($name !== NULL) { $name = urldecode($name); if ($name == '') { header('X-screen-type: error'); return WfMsg('wmu-warn3'); } else { $name = preg_replace("/[^" . Title::legalChars() . "]|:/", '-', $name); // did they give no extension at all when they changed the name? $ext = explode('.', $name); array_shift($ext); if (count($ext)) { $finalExt = $ext[count($ext) - 1]; } else { $finalExt = ''; } if ('' == $finalExt) { header('X-screen-type: error'); return wfMsg('wmu-filetype-missing'); } $title = Title::makeTitleSafe(NS_IMAGE, $name); if (is_null($title)) { header('X-screen-type: error'); return wfMsg('wmu-filetype-incorrect'); } if ($title->exists()) { if ($type == 'overwrite') { $title = Title::newFromText($name, 6); // is the target protected? $permErrors = $title->getUserPermissionsErrors('edit', $wgUser); $permErrorsUpload = $title->getUserPermissionsErrors('upload', $wgUser); $permErrorsCreate = $title->exists() ? array() : $title->getUserPermissionsErrors('create', $wgUser); if ($permErrors || $permErrorsUpload || $permErrorsCreate) { header('X-screen-type: error'); return wfMsg('wmu-file-protected'); } $file_name = new LocalFile($title, RepoGroup::singleton()->getLocalRepo()); $file_mwname = new FakeLocalFile(Title::newFromText($mwname, 6), RepoGroup::singleton()->getLocalRepo()); if (!empty($extraId)) { $flickrResult = $this->getFlickrPhotoInfo($extraId); $nsid = $flickrResult['owner']['nsid']; // e.g. 49127042@N00 $username = $flickrResult['owner']['username']; // e.g. bossa67 $license = $flickrResult['license']; $caption = '{{MediaWiki:Flickr' . intval($license) . '|1=' . wfEscapeWikiText($extraId) . '|2=' . wfEscapeWikiText($nsid) . '|3=' . wfEscapeWikiText($username) . '}}'; } else { $caption = ''; } $file_name->upload($file_mwname->getPath(), '', $caption); $file_mwname->delete(''); $this->tempFileClearInfo($tempid); $newFile = false; } else { if ($type == 'existing') { $file = wfFindFile(Title::newFromText($name, 6)); if (!empty($file)) { header('X-screen-type: existing'); $props = array(); $props['file'] = $file; $props['mwname'] = $name; $props['default_caption'] = Wikia::getProps($file->getTitle()->getArticleID(), 'default_caption'); return $this->detailsPage($props); } else { header('X-screen-type: error'); return wfMsg('wmu-file-error'); } } else { header('X-screen-type: conflict'); $tmpl = new EasyTemplate(dirname(__FILE__) . '/templates/'); // extensions check list($partname, $ext) = UploadBase::splitExtensions($name); if (count($ext)) { $finalExt = $ext[count($ext) - 1]; } else { $finalExt = ''; } // for more than one "extension" if (count($ext) > 1) { for ($i = 0; $i < count($ext) - 1; $i++) { $partname .= '.' . $ext[$i]; } } $tmpl->set_vars(array('partname' => $partname, 'extension' => strtolower($finalExt), 'mwname' => $mwname, 'extraId' => $extraId)); return $tmpl->render('conflict'); } } } else { // is the target protected? $permErrors = $title->getUserPermissionsErrors('edit', $wgUser); $permErrorsUpload = $title->getUserPermissionsErrors('upload', $wgUser); $permErrorsCreate = $title->exists() ? array() : $title->getUserPermissionsErrors('create', $wgUser); if ($permErrors || $permErrorsUpload || $permErrorsCreate) { header('X-screen-type: error'); return wfMsg('wmu-file-protected'); } $temp_file = new FakeLocalFile(Title::newFromText($mwname, 6), RepoGroup::singleton()->getLocalRepo()); $file = new LocalFile($title, RepoGroup::singleton()->getLocalRepo()); if (!empty($extraId)) { $flickrResult = $this->getFlickrPhotoInfo($extraId); $nsid = $flickrResult['owner']['nsid']; // e.g. 49127042@N00 $username = $flickrResult['owner']['username']; // e.g. bossa67 $license = $flickrResult['license']; $caption = '{{MediaWiki:Flickr' . intval($license) . '|1=' . wfEscapeWikiText($extraId) . '|2=' . wfEscapeWikiText($nsid) . '|3=' . wfEscapeWikiText($username) . '}}'; } else { // get the supplied license value $license = $wgRequest->getVal('ImageUploadLicense'); if ($license != '') { $caption = '== ' . wfMsgForContent('license') . " ==\n" . '{{' . $license . '}}' . "\n"; } else { $caption = ""; } } $file->upload($temp_file->getPath(), '', $caption); $temp_file->delete(''); $this->tempFileClearInfo($tempid); } if ($wgUser->getGLobalPreference('watchdefault') || $newFile && $wgUser->getGlobalPreference('watchcreations')) { $wgUser->addWatch($title); } $db =& wfGetDB(DB_MASTER); $db->commit(); } } else { $title = Title::newFromText($mwname, 6); } if (is_null($file)) { $file = wfFindFile($title); } if (!is_object($file)) { header('X-screen-type: error'); return wfMessage('wmu-file-not-found')->plain(); } // Test if this violates the size requirements we've been given if ($msg = $this->invalidSize($file)) { header('X-screen-type: error'); return $msg; } $ns_img = $wgContLang->getFormattedNsText(NS_IMAGE); if (-2 == $gallery && !$ck) { // this went in from the single placeholder... $name = $title->getText(); $size = $wgRequest->getVal('size'); $width = $wgRequest->getVal('width'); $layout = $wgRequest->getVal('layout'); // clear the old caption for upload $caption = $wgRequest->getVal('caption'); $slider = $wgRequest->getVal('slider'); $title_obj = Title::newFromText($title_main, $ns); $article_obj = new Article($title_obj); $text = $article_obj->getContent(); wfRunHooks('WikiaMiniUpload::fetchTextForImagePlaceholder', array(&$title_obj, &$text)); $box = $wgRequest->getVal('box', ''); $placeholder = MediaPlaceholderMatch($text, $box); $success = false; if ($placeholder) { $our_gallery = $placeholder[0]; $gallery_split = explode(':', $our_gallery); $thumb = false; $tag = $gallery_split[0] . ":" . $name; if ($size != 'full') { $tag .= '|thumb'; $thumb = true; } if (isset($width)) { $tag .= '|' . $width; } $tag .= '|' . $layout; if ($link != '') { $tag .= '|link=' . $link; } if ($caption != '') { $tag .= '|' . $caption; } $tag .= "]]"; $text = substr_replace($text, $tag, $placeholder[1], strlen($our_gallery)); // return the proper embed code with all fancies around it $embed_code = $this->generateImage($file, $name, $title_obj, $thumb, (int) str_replace('px', '', $width), $layout, $caption); $message = wfMsg('wmu-success'); Wikia::setVar('EditFromViewMode', true); $summary = wfMsg('wmu-added-from-plc'); $success = $article_obj->doEdit($text, $summary); } if ($success) { header('X-screen-type: summary'); } else { // failure signal opens js alert (BugId:4935) header('X-screen-type: error'); return; } } else { header('X-screen-type: summary'); $size = $wgRequest->getVal('size'); $width = $wgRequest->getVal('width'); $layout = $wgRequest->getVal('layout'); $caption = $wgRequest->getVal('caption'); $slider = $wgRequest->getVal('slider'); $tag = '[[' . $ns_img . ':' . $title->getDBkey(); if ($size != 'full' && ($file->getMediaType() == 'BITMAP' || $file->getMediaType() == 'DRAWING')) { $tag .= '|thumb'; if ($layout != 'right') { $tag .= '|' . $layout; } if ($slider == 'true') { $tag .= '|' . $width; } } if ($link != '' && $size == 'full') { $tag .= '|link=' . $link; } if ($caption != '') { if ($size == 'full') { $tag .= '|frame'; if ($layout != 'right') { $tag .= '|' . $layout; } } $tag .= '|' . $caption . ']]'; } else { if ($size == 'full') { $tag .= '|' . $layout; } $tag .= ']]'; } } $message = wfMsg('wmu-success'); if ($wgRequest->getVal('update_caption') == 'on') { Wikia::setProps($title->getArticleID(), array('default_caption' => $caption)); } $tmpl = new EasyTemplate(dirname(__FILE__) . '/templates/'); $tmpl->set_vars(array('tag' => $tag, 'filename' => $ns_img . ':' . $title->getDBkey(), 'message' => $message, 'code' => isset($embed_code) ? $embed_code : '')); return $tmpl->render('summary'); }
/** * This hook is called before any form of substitution or parsing is done on the text. $text is modifiable -- we can do * any sort of substitution, addition/deleting, replacement, etc. on it and it will be reflected in our output. This is * perfect to doing wiki link substitution for URL rewriting and so forth. * * @static * @param Parser $parser * @param string $text * @return boolean|string */ public static function onParserBeforeStrip(&$parser, &$text) { global $action, $wgTitle, $wgArticlePath, $wgOut, $wgPonyDocs, $action; $dbr = wfGetDB(DB_SLAVE); if (empty($wgTitle)) { return true; } // We want to do link substitution in all namespaces now. $doWikiLinkSubstitution = true; $matches = array('/^' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':(.*):(.*):(.*):(.*)/'); $doStripH1 = false; foreach ($matches as $m) { if (preg_match($m, $wgTitle->__toString())) { $doStripH1 = true; } } if (!strcmp($action, 'submit') && preg_match('/^Someone else has changed this page/i', $text)) { $text = ''; return true; } /** * Strip out ANY H1 HEADER. This has the nice effect of only stripping it out during render and not during edit or * anything. We should only be doing this for Documentation namespace? * * Note, we've put false into the if statement, because we're * disabling this "feature", per WEB-2890. * * Keeping the code in, just in case we want to re-enable. */ if ($doStripH1 && false) { $text = preg_replace('/^\\s*=.*=.*\\n?/', '', $text); } /** * Handle our wiki links, which are always of the form [[<blah>]]. There are built-in functions however that also use * this structure (like Category tags). We need to filter these out AND filter out any external links. The rest we * need to grab and produce proper anchor's and replace in the output. In each: * 0=Entire string to match * 1=Title * 2=Ignore * 3=Display Text (optional) * Possible forms: * [[TopicName]] Translated to Documentation:<currentManual>:<topicName>:<selectedVersion> * [[Documentation:<manual>:<topic>]] Translated to Documentation:<manual>:<topic>:<selectedVersion> * [[Documentation:<manual>:<topic>:<version>]]No translation done -- exact link. * [[Namespace:Topic]] No translation done -- exact link. * [[:Topic]] Link to topic in global namespace - preceding colon required! */ //if( $doWikiLinkSubstitution && preg_match_all( "/\[\[([A-Za-z0-9,:._ -]*)([|]?([A-Za-z0-9,:.'_!@\"()#$ -]*))\]\]/", $text, $matches, PREG_SET_ORDER )) if ($doWikiLinkSubstitution && preg_match_all("/\\[\\[([A-Za-z0-9,:._ -]*)(\\#[A-Za-z0-9 ._-]+)?([|]?([A-Za-z0-9,:.'_?!@\\/\"()#\$ -{}]*))\\]\\]/", $text, $matches, PREG_SET_ORDER)) { //echo '<pre>'; print_r( $matches ); die(); /** * For each, find the topic in categorylinks which is tagged with currently selected version then produce * link and replace in output ($text). Simple! */ $selectedProduct = PonyDocsProduct::GetSelectedProduct(); $selectedVersion = PonyDocsProductVersion::GetSelectedVersion($selectedProduct); $pManual = PonyDocsProductManual::GetCurrentManual($selectedProduct); // No longer bail on $pManual not being set. We should only need it // for [[Namespace:Topic]] foreach ($matches as $match) { /** * Namespace used. If NOT Documentation, just output the link. */ if (strpos($match[1], ':') !== false && strpos($match[1], PONYDOCS_DOCUMENTATION_NAMESPACE_NAME) === 0) { $pieces = explode(':', $match[1]); /** * [[Documentation:Manual:Topic]] => Documentation/<currentProduct>/<currentVersion>/Manual/Topic */ if (3 == sizeof($pieces)) { $res = $dbr->select('categorylinks', 'cl_from', array("cl_to = 'V:" . $selectedProduct . ":" . $selectedVersion . "'", 'cl_type = "page"', 'cl_sortkey LIKE "' . $dbr->strencode(strtoupper("{$pieces[1]}:{$pieces[2]}")) . ':%"'), __METHOD__); if ($res->numRows()) { global $title; // Our title is our url. We should check to see if // latest is our version. If so, we want to FORCE // the URL to include /latest/ as the version // instead of the version that the user is // currently in. $tempParts = explode("/", $title); $latest = false; if (!empty($tempParts[1]) && !strcmp($tempParts[1], "latest")) { $latest = true; } // Okay, let's determine if the VERSION that the user is in is latest, // if so, we should set latest to true. if ($selectedVersion == PonyDocsProductVersion::GetLatestReleasedVersion($selectedProduct)) { $latest = true; } $href = str_replace('$1', PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . '/' . $selectedProduct . '/' . ($latest ? "latest" : $selectedVersion) . '/' . $pieces[2] . '/' . preg_replace('/([^' . str_replace(' ', '', Title::legalChars()) . '])/', '', $pieces[3]), $wgArticlePath); $href .= $match[2]; if (isset($_SERVER['SERVER_NAME'])) { $text = str_replace($match[0], "[http://{$_SERVER['SERVER_NAME']}{$href} " . (strlen($match[4]) ? $match[4] : $match[1]) . ']', $text); } } /** * [[Documentation:Product:Manual:Topic]] => Documentation/Product/<latest_or_selected>/Manual/Topic * If linking within same product, stay on selected version; otherwise use "latest" for cross-product link */ } else { if (4 == sizeof($pieces)) { $linkProduct = $pieces[1]; // set product in link for legibility // If this is a link to the current project, use the selected version. Otherwise set version to latest. if (!strcmp($selectedProduct, $linkProduct)) { $version = $selectedVersion; } else { $version = 'latest'; } // If the version is "latest", translate that to a real version number. Use product that was in the link. if ($version == 'latest') { PonyDocsProductVersion::LoadVersionsForProduct($linkProduct); $versionObj = PonyDocsProductVersion::GetLatestReleasedVersion($linkProduct); $dbVersion = $versionObj === NULL ? NULL : $versionObj->getVersionName(); } else { $dbVersion = $version; } // Database call to see if this topic exists in the product/version specified in the link $res = $dbr->select('categorylinks', 'cl_from', array("cl_to = 'V:" . $linkProduct . ":" . $dbVersion . "'", 'cl_type = "page"', "cl_sortkey LIKE '" . $dbr->strencode(strtoupper(implode(":", array_slice($pieces, 1)))) . ":%'"), __METHOD__); if (!$res->numRows()) { // This article is not found. continue; } $href = str_replace('$1', PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . '/' . $linkProduct . '/' . $version . '/' . $pieces[2] . '/' . preg_replace('/([^' . str_replace(' ', '', Title::legalChars()) . '])/', '', $pieces[3]), $wgArticlePath); $href .= $match[2]; $text = str_replace($match[0], "[http://{$_SERVER['SERVER_NAME']}{$href} " . (strlen($match[4]) ? $match[4] : $match[1]) . ']', $text); } else { if (5 == sizeof($pieces)) { $href = str_replace('$1', PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . '/' . $pieces[1] . '/' . $pieces[4] . '/' . $pieces[2] . '/' . preg_replace('/([^' . str_replace(' ', '', Title::legalChars()) . '])/', '', $pieces[3]), $wgArticlePath); $href .= $match[2]; $text = str_replace($match[0], '[http://' . $_SERVER['SERVER_NAME'] . $href . ' ' . (strlen($match[4]) ? $match[4] : $match[1]) . ']', $text); } } } } else { // Check if our title is in Documentation and manual is set, if not, don't modify the match. if (!preg_match('/^' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':.*:.*:.*:.*/i', $wgTitle->__toString()) || !isset($pManual)) { continue; } $res = $dbr->select('categorylinks', 'cl_from', array("cl_to = 'V:" . $selectedProduct . ":" . $selectedVersion . "'", 'cl_type = "page"', "cl_sortkey LIKE '" . $dbr->strencode(strtoupper($selectedProduct . ':' . $pManual->getShortName() . ':' . $match[1])) . ":%'"), __METHOD__); /** * We might need to make it a "non-link" at this point instead of skipping it. */ if (!$res->numRows()) { continue; } $href = str_replace('$1', PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . '/' . $selectedProduct . '/' . $selectedVersion . '/' . $pManual->getShortName() . '/' . preg_replace('/([^' . str_replace(' ', '', Title::legalChars()) . '])/', '', $match[1]), $wgArticlePath); $href .= $match[2]; $text = str_replace($match[0], "[http://{$_SERVER['SERVER_NAME']}{$href} " . (strlen($match[4]) ? $match[4] : $match[1]) . ']', $text); } } } return true; }
/** * Process [[ ]] wikilinks * * @private */ function replaceInternalLinks($s) { global $wgContLang; static $fname = 'Parser::replaceInternalLinks'; wfProfileIn($fname); wfProfileIn($fname . '-setup'); static $tc = FALSE; # the % is needed to support urlencoded titles as well if (!$tc) { $tc = Title::legalChars() . '#%'; } $sk = $this->mOptions->getSkin(); #split the entire text string on occurences of [[ $a = explode('[[', ' ' . $s); #get the first element (all text up to first [[), and remove the space we added $s = array_shift($a); $s = substr($s, 1); # Match a link having the form [[namespace:link|alternate]]trail static $e1 = FALSE; if (!$e1) { $e1 = "/^([{$tc}]+)(?:\\|(.+?))?]](.*)\$/sD"; } # Match cases where there is no "]]", which might still be images static $e1_img = FALSE; if (!$e1_img) { $e1_img = "/^([{$tc}]+)\\|(.*)\$/sD"; } $useLinkPrefixExtension = $wgContLang->linkPrefixExtension(); $e2 = null; if ($useLinkPrefixExtension) { # Match the end of a line for a word that's not followed by whitespace, # e.g. in the case of 'The Arab al[[Razi]]', 'al' will be matched $e2 = wfMsgForContent('linkprefix'); } if (is_null($this->mTitle)) { throw new MWException(__METHOD__ . ": \$this->mTitle is null\n"); } $nottalk = !$this->mTitle->isTalkPage(); if ($useLinkPrefixExtension) { $m = array(); if (preg_match($e2, $s, $m)) { $first_prefix = $m[2]; } else { $first_prefix = false; } } else { $prefix = ''; } if ($wgContLang->hasVariants()) { $selflink = $wgContLang->convertLinkToAllVariants($this->mTitle->getPrefixedText()); } else { $selflink = array($this->mTitle->getPrefixedText()); } $useSubpages = $this->areSubpagesAllowed(); wfProfileOut($fname . '-setup'); # Loop for each link for ($k = 0; isset($a[$k]); $k++) { $line = $a[$k]; if ($useLinkPrefixExtension) { wfProfileIn($fname . '-prefixhandling'); if (preg_match($e2, $s, $m)) { $prefix = $m[2]; $s = $m[1]; } else { $prefix = ''; } # first link if ($first_prefix) { $prefix = $first_prefix; $first_prefix = false; } wfProfileOut($fname . '-prefixhandling'); } $might_be_img = false; wfProfileIn("{$fname}-e1"); if (preg_match($e1, $line, $m)) { # page with normal text or alt $text = $m[2]; # If we get a ] at the beginning of $m[3] that means we have a link that's something like: # [[Image:Foo.jpg|[http://example.com desc]]] <- having three ] in a row f***s up, # the real problem is with the $e1 regex # See bug 1300. # # Still some problems for cases where the ] is meant to be outside punctuation, # and no image is in sight. See bug 2095. # if ($text !== '' && substr($m[3], 0, 1) === ']' && strpos($text, '[') !== false) { $text .= ']'; # so that replaceExternalLinks($text) works later $m[3] = substr($m[3], 1); } # fix up urlencoded title texts if (strpos($m[1], '%') !== false) { # Should anchors '#' also be rejected? $m[1] = str_replace(array('<', '>'), array('<', '>'), urldecode($m[1])); } $trail = $m[3]; } elseif (preg_match($e1_img, $line, $m)) { # Invalid, but might be an image with a link in its caption $might_be_img = true; $text = $m[2]; if (strpos($m[1], '%') !== false) { $m[1] = urldecode($m[1]); } $trail = ""; } else { # Invalid form; output directly $s .= $prefix . '[[' . $line; wfProfileOut("{$fname}-e1"); continue; } wfProfileOut("{$fname}-e1"); wfProfileIn("{$fname}-misc"); # Don't allow internal links to pages containing # PROTO: where PROTO is a valid URL protocol; these # should be external links. if (preg_match('/^\\b(?:' . wfUrlProtocols() . ')/', $m[1])) { $s .= $prefix . '[[' . $line; continue; } # Make subpage if necessary if ($useSubpages) { $link = $this->maybeDoSubpageLink($m[1], $text); } else { $link = $m[1]; } $noforce = substr($m[1], 0, 1) != ':'; if (!$noforce) { # Strip off leading ':' $link = substr($link, 1); } wfProfileOut("{$fname}-misc"); wfProfileIn("{$fname}-title"); $nt = Title::newFromText($this->mStripState->unstripNoWiki($link)); if (!$nt) { $s .= $prefix . '[[' . $line; wfProfileOut("{$fname}-title"); continue; } $ns = $nt->getNamespace(); $iw = $nt->getInterWiki(); wfProfileOut("{$fname}-title"); if ($might_be_img) { # if this is actually an invalid link wfProfileIn("{$fname}-might_be_img"); if ($ns == NS_IMAGE && $noforce) { #but might be an image $found = false; while (isset($a[$k + 1])) { #look at the next 'line' to see if we can close it there $spliced = array_splice($a, $k + 1, 1); $next_line = array_shift($spliced); $m = explode(']]', $next_line, 3); if (count($m) == 3) { # the first ]] closes the inner link, the second the image $found = true; $text .= "[[{$m[0]}]]{$m[1]}"; $trail = $m[2]; break; } elseif (count($m) == 2) { #if there's exactly one ]] that's fine, we'll keep looking $text .= "[[{$m[0]}]]{$m[1]}"; } else { #if $next_line is invalid too, we need look no further $text .= '[[' . $next_line; break; } } if (!$found) { # we couldn't find the end of this imageLink, so output it raw #but don't ignore what might be perfectly normal links in the text we've examined $text = $this->replaceInternalLinks($text); $s .= "{$prefix}[[{$link}|{$text}"; # note: no $trail, because without an end, there *is* no trail wfProfileOut("{$fname}-might_be_img"); continue; } } else { #it's not an image, so output it raw $s .= "{$prefix}[[{$link}|{$text}"; # note: no $trail, because without an end, there *is* no trail wfProfileOut("{$fname}-might_be_img"); continue; } wfProfileOut("{$fname}-might_be_img"); } $wasblank = '' == $text; if ($wasblank) { $text = $link; } # Link not escaped by : , create the various objects if ($noforce) { # Interwikis wfProfileIn("{$fname}-interwiki"); if ($iw && $this->mOptions->getInterwikiMagic() && $nottalk && $wgContLang->getLanguageName($iw)) { $this->mOutput->addLanguageLink($nt->getFullText()); $s = rtrim($s . $prefix); $s .= trim($trail, "\n") == '' ? '' : $prefix . $trail; wfProfileOut("{$fname}-interwiki"); continue; } wfProfileOut("{$fname}-interwiki"); if ($ns == NS_IMAGE) { wfProfileIn("{$fname}-image"); if (!wfIsBadImage($nt->getDBkey(), $this->mTitle)) { # recursively parse links inside the image caption # actually, this will parse them in any other parameters, too, # but it might be hard to fix that, and it doesn't matter ATM $text = $this->replaceExternalLinks($text); $text = $this->replaceInternalLinks($text); # cloak any absolute URLs inside the image markup, so replaceExternalLinks() won't touch them $s .= $prefix . $this->armorLinks($this->makeImage($nt, $text)) . $trail; $this->mOutput->addImage($nt->getDBkey()); wfProfileOut("{$fname}-image"); continue; } else { # We still need to record the image's presence on the page $this->mOutput->addImage($nt->getDBkey()); } wfProfileOut("{$fname}-image"); } if ($ns == NS_CATEGORY) { wfProfileIn("{$fname}-category"); $s = rtrim($s . "\n"); # bug 87 if ($wasblank) { $sortkey = $this->getDefaultSort(); } else { $sortkey = $text; } $sortkey = Sanitizer::decodeCharReferences($sortkey); $sortkey = str_replace("\n", '', $sortkey); $sortkey = $wgContLang->convertCategoryKey($sortkey); $this->mOutput->addCategory($nt->getDBkey(), $sortkey); /** * Strip the whitespace Category links produce, see bug 87 * @todo We might want to use trim($tmp, "\n") here. */ $s .= trim($prefix . $trail, "\n") == '' ? '' : $prefix . $trail; wfProfileOut("{$fname}-category"); continue; } } # Self-link checking if ($nt->getFragment() === '') { if (in_array($nt->getPrefixedText(), $selflink, true)) { $s .= $prefix . $sk->makeSelfLinkObj($nt, $text, '', $trail); continue; } } # Special and Media are pseudo-namespaces; no pages actually exist in them if ($ns == NS_MEDIA) { $link = $sk->makeMediaLinkObj($nt, $text); # Cloak with NOPARSE to avoid replacement in replaceExternalLinks $s .= $prefix . $this->armorLinks($link) . $trail; $this->mOutput->addImage($nt->getDBkey()); continue; } elseif ($ns == NS_SPECIAL) { if (SpecialPage::exists($nt->getDBkey())) { $s .= $this->makeKnownLinkHolder($nt, $text, '', $trail, $prefix); } else { $s .= $this->makeLinkHolder($nt, $text, '', $trail, $prefix); } continue; } elseif ($ns == NS_IMAGE) { $img = wfFindFile($nt); if ($img) { // Force a blue link if the file exists; may be a remote // upload on the shared repository, and we want to see its // auto-generated page. $s .= $this->makeKnownLinkHolder($nt, $text, '', $trail, $prefix); $this->mOutput->addLink($nt); continue; } } $s .= $this->makeLinkHolder($nt, $text, '', $trail, $prefix); } wfProfileOut($fname); return $s; }
/** * Process [[ ]] wikilinks * @return LinkHolderArray * * @private */ function replaceInternalLinks2(&$s) { wfProfileIn(__METHOD__); wfProfileIn(__METHOD__ . '-setup'); static $tc = FALSE, $titleRegex; //$e1, $e1_img; if (!$tc) { # the % is needed to support urlencoded titles as well $tc = Title::legalChars() . '#%'; # Match a link having the form [[namespace:link|alternate]]trail //$e1 = "/^([{$tc}]+)(?:\\|(.+?))?]](.*)\$/sD"; # Match cases where there is no "]]", which might still be images //$e1_img = "/^([{$tc}]+)\\|(.*)\$/sD"; # Match a valid plain title $titleRegex = "/^([{$tc}]+)\$/sD"; } $holders = new LinkHolderArray($this); if (is_null($this->mTitle)) { wfProfileOut(__METHOD__); wfProfileOut(__METHOD__ . '-setup'); throw new MWException(__METHOD__ . ": \$this->mTitle is null\n"); } wfProfileOut(__METHOD__ . '-setup'); $offset = 0; $offsetStack = array(); $markers = new LinkMarkerReplacer($this, $holders, array(&$this, 'replaceInternalLinksCallback')); while (true) { $startBracketOffset = strpos($s, '[[', $offset); $endBracketOffset = strpos($s, ']]', $offset); # Finish when there are no more brackets if ($startBracketOffset === false && $endBracketOffset === false) { break; } elseif ($startBracketOffset !== false && $endBracketOffset !== false) { $isStart = $startBracketOffset <= $endBracketOffset; } else { $isStart = $startBracketOffset !== false; } $bracketOffset = $isStart ? $startBracketOffset : $endBracketOffset; if ($isStart) { /** Opening bracket **/ # Just push our current offset in the string onto the stack $offsetStack[] = $startBracketOffset; } else { /** Closing bracket **/ # Pop the start pos for our current link zone off the stack $startBracketOffset = array_pop($offsetStack); # Just to clean up the code, lets place offsets on the outer ends $endBracketOffset += 2; # Only do logic if we actually have a opening bracket for this if (isset($startBracketOffset)) { # Extract text inside the link @(list($titleText, $paramText) = explode('|', substr($s, $startBracketOffset + 2, $endBracketOffset - $startBracketOffset - 4), 2)); # Create markers only for valid links if (preg_match($titleRegex, $titleText)) { # Store the text for the marker $marker = $markers->addMarker($titleText, $paramText); # Replace the current link with the marker $s = substr($s, 0, $startBracketOffset) . $marker . substr($s, $endBracketOffset); # We have modified $s, because of this we need to set the # offset manually since the end position is different now $offset = $startBracketOffset + strlen($marker); continue; } # ToDo: Some LinkHooks may allow recursive links inside of # the link text, create a regex that also matches our # <!-- LINKMARKER ### --> sequence in titles # ToDO: Some LinkHooks use patterns rather than namespaces # these need to be tested at this point here } } # Bump our offset to after our current bracket $offset = $bracketOffset + 2; } # Now expand our tree wfProfileIn(__METHOD__ . '-expand'); $s = $markers->expand($s); wfProfileOut(__METHOD__ . '-expand'); wfProfileOut(__METHOD__); return $holders; }
/** * Generate a new file name such as "foobar 2.jpg" if both filenames * "foobar.jpg" and "foobar 1.jpg" exist in the database. * * @param $name original filename * @return new, unique filename */ public static function generateNewFilename($name) { $name = preg_replace('/[^' . Title::legalChars() . ']|[:\\/\\\\]|\\?/', '-', $name); $newName = $name; list($first, $ext) = self::splitFilenameExt($name); //blank name? give it a name! if (empty($first)) { $first = mt_rand(100000, 100000000); } $i = 1; do { $title = Title::newFromText($newName, NS_IMAGE); if (!$title->exists()) { break; } $newName = $first . ' ' . $i++ . '.' . $ext; } while ($i < 1000); return $newName; }
/** * Process [[ ]] wikilinks (RIL) * @return LinkHolderArray * * @private */ function replaceInternalLinks2(&$s) { wfProfileIn(__METHOD__); # RTE (Rich Text Editor) - begin # @author: Inez Korczyński global $wgRTEParserEnabled; # RTE (Rich Text Editor) - end wfProfileIn(__METHOD__ . '-setup'); static $tc = FALSE, $e1, $e1_img; # the % is needed to support urlencoded titles as well if (!$tc) { $tc = Title::legalChars() . '#%'; # Match a link having the form [[namespace:link|alternate]]trail $e1 = "/^([{$tc}]+)(?:\\|(.+?))?]](.*)\$/sD"; # Match cases where there is no "]]", which might still be images $e1_img = "/^([{$tc}]+)\\|(.*)\$/sD"; } $holders = new LinkHolderArray($this); # split the entire text string on occurences of [[ $a = StringUtils::explode('[[', ' ' . $s); # get the first element (all text up to first [[), and remove the space we added $s = $a->current(); $a->next(); $line = $a->current(); # Workaround for broken ArrayIterator::next() that returns "void" $s = substr($s, 1); $useLinkPrefixExtension = $this->getTargetLanguage()->linkPrefixExtension(); $e2 = null; if ($useLinkPrefixExtension) { # Match the end of a line for a word that's not followed by whitespace, # e.g. in the case of 'The Arab al[[Razi]]', 'al' will be matched $e2 = wfMsgForContent('linkprefix'); } if (is_null($this->mTitle)) { wfProfileOut(__METHOD__ . '-setup'); wfProfileOut(__METHOD__); throw new MWException(__METHOD__ . ": \$this->mTitle is null\n"); } $nottalk = !$this->mTitle->isTalkPage(); if ($useLinkPrefixExtension) { $m = array(); if (preg_match($e2, $s, $m)) { $first_prefix = $m[2]; } else { $first_prefix = false; } } else { $prefix = ''; } if ($this->getConverterLanguage()->hasVariants()) { $selflink = $this->getConverterLanguage()->autoConvertToAllVariants($this->mTitle->getPrefixedText()); } else { $selflink = array($this->mTitle->getPrefixedText()); } $useSubpages = $this->areSubpagesAllowed(); wfProfileOut(__METHOD__ . '-setup'); # Loop for each link for (; $line !== false && $line !== null; $a->next(), $line = $a->current()) { # Check for excessive memory usage if ($holders->isBig()) { # Too big # Do the existence check, replace the link holders and clear the array $holders->replace($s); $holders->clear(); } # RTE (Rich Text Editor) - begin # @author: Inez Korczyński if (!empty($wgRTEParserEnabled)) { $RTE_wikitextIdx = RTEMarker::getDataIdx(RTEMarker::INTERNAL_WIKITEXT, $line); // decode entities inside links wikimarkup (RT #38844) if ($pos = strpos($line, ']]')) { // unmark entities inside link $link = substr($line, 0, $pos); $link = RTEParser::unmarkEntities($link); // leave the rest of the line untouched $line = $link . substr($line, $pos); } } # RTE - end if ($useLinkPrefixExtension) { wfProfileIn(__METHOD__ . '-prefixhandling'); if (preg_match($e2, $s, $m)) { $prefix = $m[2]; $s = $m[1]; } else { $prefix = ''; } # first link if ($first_prefix) { $prefix = $first_prefix; $first_prefix = false; } wfProfileOut(__METHOD__ . '-prefixhandling'); } $might_be_img = false; wfProfileIn(__METHOD__ . "-e1"); if (preg_match($e1, $line, $m)) { # page with normal text or alt $text = $m[2]; # If we get a ] at the beginning of $m[3] that means we have a link that's something like: # [[Image:Foo.jpg|[http://example.com desc]]] <- having three ] in a row f***s up, # the real problem is with the $e1 regex # See bug 1300. # # Still some problems for cases where the ] is meant to be outside punctuation, # and no image is in sight. See bug 2095. # if ($text !== '' && substr($m[3], 0, 1) === ']' && strpos($text, '[') !== false) { $text .= ']'; # so that replaceExternalLinks($text) works later $m[3] = substr($m[3], 1); } # fix up urlencoded title texts if (strpos($m[1], '%') !== false) { # Should anchors '#' also be rejected? $m[1] = str_replace(array('<', '>'), array('<', '>'), rawurldecode($m[1])); } $trail = $m[3]; } elseif (preg_match($e1_img, $line, $m)) { # Invalid, but might be an image with a link in its caption $might_be_img = true; $text = $m[2]; if (strpos($m[1], '%') !== false) { $m[1] = rawurldecode($m[1]); } $trail = ""; } else { # Invalid form; output directly $s .= $prefix . '[[' . $line; wfProfileOut(__METHOD__ . "-e1"); continue; } wfProfileOut(__METHOD__ . "-e1"); wfProfileIn(__METHOD__ . "-misc"); # Don't allow internal links to pages containing # PROTO: where PROTO is a valid URL protocol; these # should be external links. if (preg_match('/^(?:' . wfUrlProtocols() . ')/', $m[1])) { $s .= $prefix . '[[' . $line; wfProfileOut(__METHOD__ . "-misc"); continue; } # Make subpage if necessary if ($useSubpages) { $link = $this->maybeDoSubpageLink($m[1], $text); } else { $link = $m[1]; } $noforce = substr($m[1], 0, 1) !== ':'; if (!$noforce) { # Strip off leading ':' $link = substr($link, 1); } wfProfileOut(__METHOD__ . "-misc"); wfProfileIn(__METHOD__ . "-title"); $nt = Title::newFromText($this->mStripState->unstripNoWiki($link)); if ($nt === null) { $s .= $prefix . '[[' . $line; wfProfileOut(__METHOD__ . "-title"); continue; } $ns = $nt->getNamespace(); $iw = $nt->getInterWiki(); wfProfileOut(__METHOD__ . "-title"); if ($might_be_img) { # if this is actually an invalid link wfProfileIn(__METHOD__ . "-might_be_img"); if ($ns == NS_FILE && $noforce) { # but might be an image $found = false; while (true) { # look at the next 'line' to see if we can close it there $a->next(); $next_line = $a->current(); if ($next_line === false || $next_line === null) { break; } $m = explode(']]', $next_line, 3); if (count($m) == 3) { # the first ]] closes the inner link, the second the image $found = true; $text .= "[[{$m[0]}]]{$m[1]}"; $trail = $m[2]; break; } elseif (count($m) == 2) { # if there's exactly one ]] that's fine, we'll keep looking $text .= "[[{$m[0]}]]{$m[1]}"; } else { # if $next_line is invalid too, we need look no further $text .= '[[' . $next_line; break; } } if (!$found) { # we couldn't find the end of this imageLink, so output it raw # but don't ignore what might be perfectly normal links in the text we've examined $holders->merge($this->replaceInternalLinks2($text)); $s .= "{$prefix}[[{$link}|{$text}"; # note: no $trail, because without an end, there *is* no trail wfProfileOut(__METHOD__ . "-might_be_img"); continue; } } else { # it's not an image, so output it raw $s .= "{$prefix}[[{$link}|{$text}"; # note: no $trail, because without an end, there *is* no trail wfProfileOut(__METHOD__ . "-might_be_img"); continue; } wfProfileOut(__METHOD__ . "-might_be_img"); } $wasblank = $text == ''; if ($wasblank) { $text = $link; } else { # Bug 4598 madness. Handle the quotes only if they come from the alternate part # [[Lista d''e paise d''o munno]] -> <a href="...">Lista d''e paise d''o munno</a> # [[Criticism of Harry Potter|Criticism of ''Harry Potter'']] # -> <a href="Criticism of Harry Potter">Criticism of <i>Harry Potter</i></a> $text = $this->doQuotes($text); } # Link not escaped by : , create the various objects if ($noforce) { global $wgContLang; # Interwikis if (empty($wgRTEParserEnabled)) { # wikia wfProfileIn(__METHOD__ . "-interwiki"); if ($iw && $this->mOptions->getInterwikiMagic() && $nottalk && $wgContLang->getLanguageName($iw)) { $this->mOutput->addLanguageLink($nt->getFullText()); $s = rtrim($s . $prefix); $s .= trim($trail, "\n") == '' ? '' : $prefix . $trail; wfProfileOut(__METHOD__ . "-interwiki"); continue; } wfProfileOut(__METHOD__ . "-interwiki"); } # wikia if ($ns == NS_FILE) { wfProfileIn(__METHOD__ . "-image"); if (!wfIsBadImage($nt->getDBkey(), $this->mTitle)) { if ($wasblank) { # if no parameters were passed, $text # becomes something like "File:Foo.png", # which we don't want to pass on to the # image generator $text = ''; } else { # recursively parse links inside the image caption # actually, this will parse them in any other parameters, too, # but it might be hard to fix that, and it doesn't matter ATM $text = $this->replaceExternalLinks($text); $holders->merge($this->replaceInternalLinks2($text)); } # RTE (Rich Text Editor) - begin # @author: Inez Korczyński if (!empty($wgRTEParserEnabled)) { $text = RTEMarker::generate(RTEMarker::IMAGE_DATA, $RTE_wikitextIdx) . $text; } # RTE - end # cloak any absolute URLs inside the image markup, so replaceExternalLinks() won't touch them /** wikia $s .= $prefix . $this->armorLinks( $this->makeImage( $nt, $text, $holders ) ) . $trail; wikia **/ # cater for new placeholder-in-template namespace - Bartek # TODO: Get the hell out with this code from here this can be done in hook handler fired in makeImage function - Inez if ("Template Placeholder" != $nt->getText()) { $s .= $prefix . $this->armorLinks($this->makeImage($nt, $text, $holders)) . $trail; } else { $s .= $prefix . $this->armorLinks(ImagePlaceholder_makeDullImage($nt, $text, $holders)) . $trail; } } else { $s .= $prefix . $trail; } wfProfileOut(__METHOD__ . "-image"); continue; } if ($ns == NS_CATEGORY) { wfProfileIn(__METHOD__ . "-category"); # RTE (Rich Text Editor) - begin # @author: Inez Korczyński # Category handling if (!empty($wgRTEParserEnabled)) { $dataIdx = RTEData::put('placeholder', array('type' => 'category', 'wikitextIdx' => $RTE_wikitextIdx)); $s .= $prefix . RTEMarker::generate(RTEMarker::PLACEHOLDER, $dataIdx) . $trail; } else { $s = rtrim($s . "\n"); # bug 87 if ($wasblank) { $sortkey = $this->getDefaultSort(); } else { $sortkey = $text; } $sortkey = Sanitizer::decodeCharReferences($sortkey); $sortkey = str_replace("\n", '', $sortkey); $sortkey = $this->getConverterLanguage()->convertCategoryKey($sortkey); $this->mOutput->addCategory($nt->getDBkey(), $sortkey); /** * Strip the whitespace Category links produce, see bug 87 * @todo We might want to use trim($tmp, "\n") here. */ $s .= trim($prefix . $trail, "\n") == '' ? '' : $prefix . $trail; } wfProfileOut(__METHOD__ . "-category"); continue; } # Wikia change begin # @author macbre $hookRet = wfRunHooks('ParserReplaceInternalLinks2NoForce', array(&$s, $nt, $prefix, $trail, isset($RTE_wikitextIdx) ? $RTE_wikitextIdx : null)); if ($hookRet === false) { continue; } # Wikia change end } # RTE (Rich Text Editor) - begin # @author: Inez Korczyński # No special handling for self-linking in RTE mode # Self-link checking if (empty($wgRTEParserEnabled) && $nt->getFragment() === '' && $ns != NS_SPECIAL) { if (in_array($nt->getPrefixedText(), $selflink, true)) { $s .= $prefix . Linker::makeSelfLinkObj($nt, $text, '', $trail); continue; } } # RTE - end # NS_MEDIA is a pseudo-namespace for linking directly to a file # @todo FIXME: Should do batch file existence checks, see comment below if ($ns == NS_MEDIA) { # RTE (Rich Text Editor) - begin # @author: macbre # BugId:1694 - handle [[Media:xxx]] as placeholders if (!empty($wgRTEParserEnabled)) { $dataIdx = RTEData::put('placeholder', array('type' => 'media', 'wikitextIdx' => $RTE_wikitextIdx)); $s .= $prefix . RTEMarker::generate(RTEMarker::PLACEHOLDER, $dataIdx) . $trail; continue; } # RTE - end wfProfileIn(__METHOD__ . "-media"); # Give extensions a chance to select the file revision for us $options = array(); $descQuery = false; wfRunHooks('BeforeParserFetchFileAndTitle', array($this, $nt, &$options, &$descQuery)); # Fetch and register the file (file title may be different via hooks) list($file, $nt) = $this->fetchFileAndTitle($nt, $options); # Cloak with NOPARSE to avoid replacement in replaceExternalLinks $s .= $prefix . $this->armorLinks(Linker::makeMediaLinkFile($nt, $file, $text)) . $trail; wfProfileOut(__METHOD__ . "-media"); continue; } wfProfileIn(__METHOD__ . "-always_known"); # RTE (Rich Text Editor) - begin # @author: Inez Korczyński if (!empty($wgRTEParserEnabled)) { $text = RTEMarker::generate(RTEMarker::INTERNAL_DATA, RTEData::put('data', array('type' => 'internal', 'wikitextIdx' => $RTE_wikitextIdx, 'text' => $text, 'link' => $link, 'wasblank' => $wasblank, 'noforce' => $noforce))) . $text; } # RTE - end # Some titles, such as valid special pages or files in foreign repos, should # be shown as bluelinks even though they're not included in the page table # # @todo FIXME: isAlwaysKnown() can be expensive for file links; we should really do # batch file existence checks for NS_FILE and NS_MEDIA if ($iw == '' && $nt->isAlwaysKnown()) { $this->mOutput->addLink($nt); $s .= $this->makeKnownLinkHolder($nt, $text, array(), $trail, $prefix); } else { # Links will be added to the output link list after checking $s .= $holders->makeHolder($nt, $text, array(), $trail, $prefix); } wfProfileOut(__METHOD__ . "-always_known"); } wfProfileOut(__METHOD__); return $holders; }
/** * Secure and split - main initialisation function for this object * * Assumes that mDbkeyform has been set, and is urldecoded * and uses underscores, but not otherwise munged. This function * removes illegal characters, splits off the interwiki and * namespace prefixes, sets the other forms, and canonicalizes * everything. * @return bool true on success */ private function secureAndSplit() { global $wgContLang, $wgLocalInterwiki, $wgCapitalLinks; # Initialisation static $rxTc = false; if (!$rxTc) { # % is needed as well $rxTc = '/[^' . Title::legalChars() . ']|%[0-9A-Fa-f]{2}/S'; } $this->mInterwiki = $this->mFragment = ''; $this->mNamespace = $this->mDefaultNamespace; # Usually NS_MAIN $dbkey = $this->mDbkeyform; # Strip Unicode bidi override characters. # Sometimes they slip into cut-n-pasted page titles, where the # override chars get included in list displays. $dbkey = str_replace("", '', $dbkey); // 200E LEFT-TO-RIGHT MARK $dbkey = str_replace("", '', $dbkey); // 200F RIGHT-TO-LEFT MARK # Clean up whitespace # $dbkey = preg_replace('/[ _]+/', '_', $dbkey); $dbkey = trim($dbkey, '_'); if ('' == $dbkey) { return false; } if (false !== strpos($dbkey, UTF8_REPLACEMENT)) { # Contained illegal UTF-8 sequences or forbidden Unicode chars. return false; } $this->mDbkeyform = $dbkey; # Initial colon indicates main namespace rather than specified default # but should not create invalid {ns,title} pairs such as {0,Project:Foo} if (':' == $dbkey[0]) { $this->mNamespace = NS_MAIN; $dbkey = substr($dbkey, 1); # remove the colon but continue processing $dbkey = trim($dbkey, '_'); # remove any subsequent whitespace } # Namespace or interwiki prefix $firstPass = true; do { $m = array(); if (preg_match("/^(.+?)_*:_*(.*)\$/S", $dbkey, $m)) { $p = $m[1]; if ($ns = $wgContLang->getNsIndex($p)) { # Ordinary namespace $dbkey = $m[2]; $this->mNamespace = $ns; } elseif ($this->getInterwikiLink($p)) { if (!$firstPass) { # Can't make a local interwiki link to an interwiki link. # That's just crazy! return false; } # Interwiki link $dbkey = $m[2]; $this->mInterwiki = $wgContLang->lc($p); # Redundant interwiki prefix to the local wiki if (0 == strcasecmp($this->mInterwiki, $wgLocalInterwiki)) { if ($dbkey == '') { # Can't have an empty self-link return false; } $this->mInterwiki = ''; $firstPass = false; # Do another namespace split... continue; } # If there's an initial colon after the interwiki, that also # resets the default namespace if ($dbkey !== '' && $dbkey[0] == ':') { $this->mNamespace = NS_MAIN; $dbkey = substr($dbkey, 1); } } # If there's no recognized interwiki or namespace, # then let the colon expression be part of the title. } break; } while (true); # We already know that some pages won't be in the database! # if ('' != $this->mInterwiki || NS_SPECIAL == $this->mNamespace) { $this->mArticleID = 0; } $fragment = strstr($dbkey, '#'); if (false !== $fragment) { $this->setFragment($fragment); $dbkey = substr($dbkey, 0, strlen($dbkey) - strlen($fragment)); # remove whitespace again: prevents "Foo_bar_#" # becoming "Foo_bar_" $dbkey = preg_replace('/_*$/', '', $dbkey); } # Reject illegal characters. # if (preg_match($rxTc, $dbkey)) { return false; } /** * Pages with "/./" or "/../" appearing in the URLs will * often be unreachable due to the way web browsers deal * with 'relative' URLs. Forbid them explicitly. */ if (strpos($dbkey, '.') !== false && ($dbkey === '.' || $dbkey === '..' || strpos($dbkey, './') === 0 || strpos($dbkey, '../') === 0 || strpos($dbkey, '/./') !== false || strpos($dbkey, '/../') !== false)) { return false; } /** * Magic tilde sequences? Nu-uh! */ if (strpos($dbkey, '~~~') !== false) { return false; } /** * Limit the size of titles to 255 bytes. * This is typically the size of the underlying database field. * We make an exception for special pages, which don't need to be stored * in the database, and may edge over 255 bytes due to subpage syntax * for long titles, e.g. [[Special:Block/Long name]] */ if ($this->mNamespace != NS_SPECIAL && strlen($dbkey) > 255 || strlen($dbkey) > 512) { return false; } /** * Normally, all wiki links are forced to have * an initial capital letter so [[foo]] and [[Foo]] * point to the same place. * * Don't force it for interwikis, since the other * site might be case-sensitive. */ if ($wgCapitalLinks && $this->mInterwiki == '') { $dbkey = $wgContLang->ucfirst($dbkey); } /** * Can't make a link to a namespace alone... * "empty" local links can only be self-links * with a fragment identifier. */ if ($dbkey == '' && $this->mInterwiki == '' && $this->mNamespace != NS_MAIN) { return false; } // Any remaining initial :s are illegal. if ($dbkey !== '' && ':' == $dbkey[0]) { return false; } # Fill fields $this->mDbkeyform = $dbkey; $this->mUrlform = ilWikiUtil::wfUrlencode($dbkey); $this->mTextform = str_replace('_', ' ', $dbkey); return true; }
/** * Really do the upload * Checks are made in SpecialUpload::execute() * @access private */ function processUpload() { global $wgUser, $wgOut; /* Check for PHP error if any, requires php 4.2 or newer */ if ($this->mUploadError == 1) { $this->mainUploadForm(wfMsgHtml('largefileserver')); return; } /** * If there was no filename or a zero size given, give up quick. */ if (trim($this->mOname) == '' || empty($this->mUploadSize)) { $this->mainUploadForm(wfMsgHtml('emptyfile')); return; } # Chop off any directories in the given filename if ($this->mDestFile) { $basename = wfBaseName($this->mDestFile); } else { $basename = wfBaseName($this->mOname); } /** * We'll want to blacklist against *any* 'extension', and use * only the final one for the whitelist. */ list($partname, $ext) = $this->splitExtensions($basename); if (count($ext)) { $finalExt = $ext[count($ext) - 1]; } else { $finalExt = ''; } $fullExt = implode('.', $ext); # If there was more than one "extension", reassemble the base # filename to prevent bogus complaints about length if (count($ext) > 1) { for ($i = 0; $i < count($ext) - 1; $i++) { $partname .= '.' . $ext[$i]; } } if (strlen($partname) < 3) { $this->mainUploadForm(wfMsgHtml('minlength')); return; } // WERELATE - added validation tests if (!$this->mLicense && !$this->mReUploading) { $this->uploadError("You must select a license (press the \"back button\" on your browser to correct this)"); return; } /** * Filter out illegal characters, and try to make a legible name * out of it. We'll strip some silently that Title would die on. */ $filtered = preg_replace("/[^" . Title::legalChars() . "]|:/", '-', $basename); $nt = Title::newFromText($filtered); if (is_null($nt)) { $this->uploadError(wfMsgWikiHtml('illegalfilename', htmlspecialchars($filtered))); return; } $nt =& Title::makeTitle(NS_IMAGE, $nt->getDBkey()); $this->mUploadSaveName = $nt->getDBkey(); /** * If the image is protected, non-sysop users won't be able * to modify it by uploading a new revision. */ if (!$nt->userCanEdit()) { return $this->uploadError(wfMsgWikiHtml('protectedpage')); } /** * In some cases we may forbid overwriting of existing files. */ $overwrite = $this->checkOverwrite($this->mUploadSaveName); if (WikiError::isError($overwrite)) { return $this->uploadError($overwrite->toString()); } /* Don't allow users to override the blacklist (check file extension) */ global $wgStrictFileExtensions; global $wgFileExtensions, $wgFileBlacklist; if ($this->checkFileExtensionList($ext, $wgFileBlacklist) || $wgStrictFileExtensions && !$this->checkFileExtension($finalExt, $wgFileExtensions)) { return $this->uploadError(wfMsgHtml('badfiletype', htmlspecialchars($fullExt))); } /** * Look at the contents of the file; if we can recognize the * type but it's corrupt or data of the wrong type, we should * probably not accept it. */ if (!$this->mStashed) { $this->checkMacBinary(); $veri = $this->verify($this->mUploadTempName, $finalExt); if ($veri !== true) { //it's a wiki error... return $this->uploadError($veri->toString()); } } /** * Provide an opportunity for extensions to add futher checks */ $error = ''; if (!wfRunHooks('UploadVerification', array($this->mUploadSaveName, $this->mUploadTempName, &$error))) { return $this->uploadError($error); } /** * Check for non-fatal conditions */ if (!$this->mIgnoreWarning) { $warning = ''; global $wgCapitalLinks; if ($wgCapitalLinks) { $filtered = ucfirst($filtered); } if ($this->mUploadSaveName != $filtered) { $warning .= '<li>' . wfMsgHtml('badfilename', htmlspecialchars($this->mUploadSaveName)) . '</li>'; } global $wgCheckFileExtensions; if ($wgCheckFileExtensions) { if (!$this->checkFileExtension($finalExt, $wgFileExtensions)) { $warning .= '<li>' . wfMsgHtml('badfiletype', htmlspecialchars($fullExt)) . '</li>'; } } global $wgUploadSizeWarning; if ($wgUploadSizeWarning && $this->mUploadSize > $wgUploadSizeWarning) { # TODO: Format $wgUploadSizeWarning to something that looks better than the raw byte # value, perhaps add GB,MB and KB suffixes? $warning .= '<li>' . wfMsgHtml('largefile', $wgUploadSizeWarning, $this->mUploadSize) . '</li>'; } if ($this->mUploadSize == 0) { $warning .= '<li>' . wfMsgHtml('emptyfile') . '</li>'; } if ($nt->getArticleID()) { global $wgUser; $sk = $wgUser->getSkin(); $dlink = $sk->makeKnownLinkObj($nt); $warning .= '<li>' . wfMsgHtml('fileexists', $dlink) . '</li>'; // WERELATE: added fileexistsnoreupload warning; assume that if user entered license, then this isn't a case of purposeful re-uploading if ($this->mLicense) { $warning .= '<li>' . wfMsgHtml('fileexistsnoreupload') . '</li>'; } } else { # If the file existed before and was deleted, warn the user of this # Don't bother doing so if the image exists now, however // WERELATE: remove // $image = new Image( $nt ); // if( $image->wasDeleted() ) { // $skin = $wgUser->getSkin(); // $ltitle = Title::makeTitle( NS_SPECIAL, 'Log' ); // $llink = $skin->makeKnownLinkObj( $ltitle, wfMsgHtml( 'deletionlog' ), 'type=delete&page=' . $nt->getPrefixedUrl() ); // $warning .= wfOpenElement( 'li' ) . wfMsgWikiHtml( 'filewasdeleted', $llink ) . wfCloseElement( 'li' ); // } } if ($warning != '') { /** * Stash the file in a temporary location; the user can choose * to let it through and we'll complete the upload then. */ return $this->uploadWarning($warning); } } /** * Try actually saving the thing... * It will show an error form on failure. */ $hasBeenMunged = !empty($this->mSessionKey) || $this->mRemoveTempFile; if ($this->saveUploadedFile($this->mUploadSaveName, $this->mUploadTempName, $hasBeenMunged)) { /** * Update the upload log and create the description page * if it's a new file. */ $img = Image::newFromName($this->mUploadSaveName); // WERELATE - changed - added getMetadata, null out license (because we capture it in metadata), redirect only if target is empty $success = $img->recordUpload($this->mUploadOldVersion, $this->mUploadDescription, '', $this->mUploadCopyStatus, $this->mUploadSource, $this->mWatchthis, $this->getMetadata(), !$this->mTarget); if ($success) { // WERELATE - if we're uploading for a P/F target, showSuccess, else just redirect if ($this->mTarget) { $this->showSuccess(); } else { $article = new Article($img->getTitle()); $article->doRedirect(); } wfRunHooks('UploadComplete', array(&$img)); } else { // Image::recordUpload() fails if the image went missing, which is // unlikely, hence the lack of a specialised message $wgOut->showFileNotFoundError($this->mUploadSaveName); } } }
/** * Replace all invalid characters with - * Additional characters can be defined in $wgIllegalFileChars (see bug 20489) * By default, $wgIllegalFileChars = ':' * * @param string $name Filename to process * @return string */ function wfStripIllegalFilenameChars($name) { global $wgIllegalFileChars; $illegalFileChars = $wgIllegalFileChars ? "|[" . $wgIllegalFileChars . "]" : ''; $name = wfBaseName($name); $name = preg_replace("/[^" . Title::legalChars() . "]" . $illegalFileChars . "/", '-', $name); return $name; }
private function buildSafeTitle($name) { $x = preg_replace_callback('/([^' . Title::legalChars() . ']|~)/', array($this, 'hexChar'), $name); $test = Title::makeTitleSafe(NS_FILE, $x); if (is_null($test) || $test->getDBkey() !== $x) { $this->error("Unable to generate safe title from '{$name}', got '{$x}'"); return false; } return $x; }
/** * Pre-save transform helper function * * @param $text string * @param $user User * * @return string */ private function pstPass2($text, $user) { global $wgContLang; # Note: This is the timestamp saved as hardcoded wikitext to # the database, we use $wgContLang here in order to give # everyone the same signature and use the default one rather # than the one selected in each user's preferences. # (see also bug 12815) $ts = $this->mOptions->getTimestamp(); $timestamp = MWTimestamp::getLocalInstance($ts); $ts = $timestamp->format('YmdHis'); $tzMsg = $timestamp->format('T'); # might vary on DST changeover! # Allow translation of timezones through wiki. format() can return # whatever crap the system uses, localised or not, so we cannot # ship premade translations. $key = 'timezone-' . strtolower(trim($tzMsg)); $msg = wfMessage($key)->inContentLanguage(); if ($msg->exists()) { $tzMsg = $msg->text(); } $d = $wgContLang->timeanddate($ts, false, false) . " ({$tzMsg})"; # Variable replacement # Because mOutputType is OT_WIKI, this will only process {{subst:xxx}} type tags $text = $this->replaceVariables($text); # This works almost by chance, as the replaceVariables are done before the getUserSig(), # which may corrupt this parser instance via its wfMessage()->text() call- # Signatures $sigText = $this->getUserSig($user); $text = strtr($text, array('~~~~~' => $d, '~~~~' => "{$sigText} {$d}", '~~~' => $sigText)); # Context links ("pipe tricks"): [[|name]] and [[name (context)|]] $tc = '[' . Title::legalChars() . ']'; $nc = '[ _0-9A-Za-z\\x80-\\xff-]'; # Namespaces can use non-ascii! $p1 = "/\\[\\[(:?{$nc}+:|:|)({$tc}+?)( ?\\({$tc}+\\))\\|]]/"; # [[ns:page (context)|]] $p4 = "/\\[\\[(:?{$nc}+:|:|)({$tc}+?)( ?({$tc}+))\\|]]/"; # [[ns:page(context)|]] (double-width brackets, added in r40257) $p3 = "/\\[\\[(:?{$nc}+:|:|)({$tc}+?)( ?\\({$tc}+\\)|)((?:, |,){$tc}+|)\\|]]/"; # [[ns:page (context), context|]] (using either single or double-width comma) $p2 = "/\\[\\[\\|({$tc}+)]]/"; # [[|page]] (reverse pipe trick: add context from page title) # try $p1 first, to turn "[[A, B (C)|]]" into "[[A, B (C)|A, B]]" $text = preg_replace($p1, '[[\\1\\2\\3|\\2]]', $text); $text = preg_replace($p4, '[[\\1\\2\\3|\\2]]', $text); $text = preg_replace($p3, '[[\\1\\2\\3\\4|\\2]]', $text); $t = $this->mTitle->getText(); $m = array(); if (preg_match("/^({$nc}+:|){$tc}+?( \\({$tc}+\\))\$/", $t, $m)) { $text = preg_replace($p2, "[[{$m['1']}\\1{$m['2']}|\\1]]", $text); } elseif (preg_match("/^({$nc}+:|){$tc}+?(, {$tc}+|)\$/", $t, $m) && "{$m['1']}{$m['2']}" != '') { $text = preg_replace($p2, "[[{$m['1']}\\1{$m['2']}|\\1]]", $text); } else { # if there's no context, don't bother duplicating the title $text = preg_replace($p2, '[[\\1]]', $text); } # Trim trailing whitespace $text = rtrim($text); return $text; }
/** * Parses a media link. * This is a very small subset of Parser::replaceInternalLinks() that * parses a single image or media link, and returns the parsed text, * as well as a File instance of the referenced media, if available. * * @return Three-element array containing the matched parts of the link, * and the file object, or NULL. */ private static function parseMediaLink( &$parser, $text ) { $tc = Title::legalChars(); if ( !preg_match( "/\\[\\[([{$tc}]+)(?:\\|(.+?))?]]/", $text, $m ) ) return null; $nt = Title::newFromText( $m[1] ); if ( !$nt ) return null; $ns = $nt->getNamespace(); if ( $ns == NS_IMAGE || $ns == NS_MEDIA ) { $parser->mOutput->addLink( $nt ); return @ array( $m[1], $m[2], wfFindFile( $nt ) ); } else { return null; } }
protected function appendGeneralInfo($property) { global $wgContLang; $config = $this->getConfig(); $data = array(); $mainPage = Title::newMainPage(); $data['mainpage'] = $mainPage->getPrefixedText(); $data['base'] = wfExpandUrl($mainPage->getFullURL(), PROTO_CURRENT); $data['sitename'] = $config->get('Sitename'); // wgLogo can either be a relative or an absolute path // make sure we always return an absolute path $data['logo'] = wfExpandUrl($config->get('Logo'), PROTO_RELATIVE); $data['generator'] = "MediaWiki {$config->get('Version')}"; $data['phpversion'] = PHP_VERSION; $data['phpsapi'] = PHP_SAPI; if (defined('HHVM_VERSION')) { $data['hhvmversion'] = HHVM_VERSION; } $data['dbtype'] = $config->get('DBtype'); $data['dbversion'] = $this->getDB()->getServerVersion(); $allowFrom = array(''); $allowException = true; if (!$config->get('AllowExternalImages')) { $data['imagewhitelistenabled'] = (bool) $config->get('EnableImageWhitelist'); $allowFrom = $config->get('AllowExternalImagesFrom'); $allowException = !empty($allowFrom); } if ($allowException) { $data['externalimages'] = (array) $allowFrom; ApiResult::setIndexedTagName($data['externalimages'], 'prefix'); } $data['langconversion'] = !$config->get('DisableLangConversion'); $data['titleconversion'] = !$config->get('DisableTitleConversion'); if ($wgContLang->linkPrefixExtension()) { $linkPrefixCharset = $wgContLang->linkPrefixCharset(); $data['linkprefixcharset'] = $linkPrefixCharset; // For backwards compatibility $data['linkprefix'] = "/^((?>.*[^{$linkPrefixCharset}]|))(.+)\$/sDu"; } else { $data['linkprefixcharset'] = ''; $data['linkprefix'] = ''; } $linktrail = $wgContLang->linkTrail(); $data['linktrail'] = $linktrail ?: ''; $data['legaltitlechars'] = Title::legalChars(); global $IP; $git = SpecialVersion::getGitHeadSha1($IP); if ($git) { $data['git-hash'] = $git; $data['git-branch'] = SpecialVersion::getGitCurrentBranch($GLOBALS['IP']); } else { $svn = SpecialVersion::getSvnRevision($IP); if ($svn) { $data['rev'] = $svn; } } // 'case-insensitive' option is reserved for future $data['case'] = $config->get('CapitalLinks') ? 'first-letter' : 'case-sensitive'; $data['lang'] = $config->get('LanguageCode'); $fallbacks = array(); foreach ($wgContLang->getFallbackLanguages() as $code) { $fallbacks[] = array('code' => $code); } $data['fallback'] = $fallbacks; ApiResult::setIndexedTagName($data['fallback'], 'lang'); if ($wgContLang->hasVariants()) { $variants = array(); foreach ($wgContLang->getVariants() as $code) { $variants[] = array('code' => $code, 'name' => $wgContLang->getVariantname($code)); } $data['variants'] = $variants; ApiResult::setIndexedTagName($data['variants'], 'lang'); } $data['rtl'] = $wgContLang->isRTL(); $data['fallback8bitEncoding'] = $wgContLang->fallback8bitEncoding(); $data['readonly'] = wfReadOnly(); if ($data['readonly']) { $data['readonlyreason'] = wfReadOnlyReason(); } $data['writeapi'] = (bool) $config->get('EnableWriteAPI'); $tz = $config->get('Localtimezone'); $offset = $config->get('LocalTZoffset'); if (is_null($tz)) { $tz = 'UTC'; $offset = 0; } elseif (is_null($offset)) { $offset = 0; } $data['timezone'] = $tz; $data['timeoffset'] = intval($offset); $data['articlepath'] = $config->get('ArticlePath'); $data['scriptpath'] = $config->get('ScriptPath'); $data['script'] = $config->get('Script'); $data['variantarticlepath'] = $config->get('VariantArticlePath'); $data[ApiResult::META_BC_BOOLS][] = 'variantarticlepath'; $data['server'] = $config->get('Server'); $data['servername'] = $config->get('ServerName'); $data['wikiid'] = wfWikiID(); $data['time'] = wfTimestamp(TS_ISO_8601, time()); $data['misermode'] = (bool) $config->get('MiserMode'); $data['maxuploadsize'] = UploadBase::getMaxUploadSize(); $data['minuploadchunksize'] = (int) $this->getConfig()->get('MinUploadChunkSize'); $data['thumblimits'] = $config->get('ThumbLimits'); ApiResult::setArrayType($data['thumblimits'], 'BCassoc'); ApiResult::setIndexedTagName($data['thumblimits'], 'limit'); $data['imagelimits'] = array(); ApiResult::setArrayType($data['imagelimits'], 'BCassoc'); ApiResult::setIndexedTagName($data['imagelimits'], 'limit'); foreach ($config->get('ImageLimits') as $k => $limit) { $data['imagelimits'][$k] = array('width' => $limit[0], 'height' => $limit[1]); } $favicon = $config->get('Favicon'); if (!empty($favicon)) { // wgFavicon can either be a relative or an absolute path // make sure we always return an absolute path $data['favicon'] = wfExpandUrl($favicon, PROTO_RELATIVE); } Hooks::run('APIQuerySiteInfoGeneralInfo', array($this, &$data)); return $this->getResult()->addValue('query', $property, $data); }
/** * Replace all invalid characters with - * @param mixed $title Filename to process */ function wfStripIllegalFilenameChars($name) { $name = wfBaseName($name); $name = preg_replace("/[^" . Title::legalChars() . "]|:/", '-', $name); return $name; }
public static function makeTitleValid($text) { $text = self::stripWikitext($text); $text = html_entity_decode($text, ENT_QUOTES, 'UTF-8'); static $rxTc; if (is_callable('MediaWikiTitleCodec::getTitleInvalidRegex')) { $rxTc = MediaWikiTitleCodec::getTitleInvalidRegex(); } elseif (is_callable(array('Title', 'getTitleInvalidRegex'))) { // Pre-1.25 compat $rxTc = Title::getTitleInvalidRegex(); } elseif (!$rxTc) { // Back-compat $rxTc = '/' . '[^' . Title::legalChars() . ']' . '|%[0-9A-Fa-f]{2}' . '|&[A-Za-z0-9\\x80-\\xff]+;' . '|&#[0-9]+;' . '|&#x[0-9A-Fa-f]+;' . '/S'; } $text = preg_replace($rxTc, '_', $text); return $text; }
/** * Add a new video file into the mediawiki infrastructure so that it can * be accessed as {{whvid|filename.mp4|Preview.jpg}} */ public function addWikiHowVideo($articleId, &$video) { // find name for video; change filename to Filename 1.jpg if // Filename.jpg already existed $regexp = '/[^' . Title::legalChars() . ']+/'; $first = preg_replace($regexp, '', $video['first']); // Let's also remove " and ' since s3 doesn't seem to like $first = preg_replace('/["\']+/', '', $first); $ext = $video['ext']; $newName = $first . '.' . $ext; $i = 1; do { if (!WikiVideo::fileExists($newName)) { break; } $newName = $first . ' Version ' . ++$i . '.' . $ext; } while ($i <= 1000); // Move the file from one s3 bucket to another $ret = WikiVideo::copyFileToProd(WikiVisualTranscoder::AWS_TRANSCODING_OUT_BUCKET, $video['aws_uri_out'], $newName); if ($ret['error']) { return $ret['error']; } // instruct later processing about which mediawiki name was used $video['mediawikiName'] = $newName; // Add preview image $img = $video; $img['ext'] = 'jpg'; $err = Mp4Transcoder::addMediawikiImage($articleId, $img); if ($err) { return 'Unable to add preview image: ' . $err; } else { $video['previewMediawikiName'] = $img['mediawikiName']; // Cleanup temporary preview image if (!empty($img['filename'])) { $rmCmd = "rm " . $img['filename']; system($rmCmd); } } self::d(">>> addWikiHowVideo: video['mediawikiName']=" . $video['mediawikiName'] . ", video['previewMediawikiName']=" . $video['previewMediawikiName']); // Keep a log of where videos were uploaded in wikivideo_video_names table $dbw = WikiVisualTranscoder::getDB('write'); $vidname = $articleID . '/' . $video['name']; $sql = 'INSERT INTO wikivisual_vid_names SET filename=' . $dbw->addQuotes($vidname) . ', wikiname=' . $dbw->addQuotes($video['mediawikiName']); $dbw->query($sql, __METHOD__); return ''; }