/**
  * Get name of the user this page referrs to
  */
 public static function getUserName(Title $title, $namespaces, $fallbackToGlobal = true)
 {
     wfProfileIn(__METHOD__);
     global $wgUser, $wgRequest;
     $userName = null;
     if (in_array($title->getNamespace(), $namespaces)) {
         // get "owner" of this user / user talk / blog page
         $parts = explode('/', $title->getText());
     } else {
         if ($title->getNamespace() == NS_SPECIAL) {
             if ($title->isSpecial('Following') || $title->isSpecial('Contributions')) {
                 $target = $wgRequest->getText('target');
                 if ($target != '') {
                     // /wiki/Special:Contributions?target=FooBar (RT #68323)
                     $parts = array($target);
                 } else {
                     // get user this special page referrs to
                     $parts = explode('/', $wgRequest->getText('title', false));
                     // remove special page name
                     array_shift($parts);
                 }
             }
         }
     }
     if (isset($parts[0]) && $parts[0] != '') {
         //this line was usign urldecode($parts[0]) before, see RT #107278, user profile pages with '+' symbols get 'non-existing' message
         $userName = str_replace('_', ' ', $parts[0]);
     } elseif ($fallbackToGlobal) {
         // fallback value
         $userName = $wgUser->getName();
     }
     wfProfileOut(__METHOD__);
     return $userName;
 }
 /**
  * @param Title|null $title
  *
  * @return bool
  */
 public function isInvalidLoginRedirect($title)
 {
     return !$title instanceof Title || $title->isSpecial('Userlogout') || $title->isSpecial('Signup') || $title->isSpecial('Connect') || $title->isSpecial('FacebookConnect') || $title->isSpecial('UserLogin');
 }
 /**
  * Replace the MediaWiki login/logout links with direct links to SimpleSamlPhp.
  * This takes away the need to set up a redirect on the special UserLogin and UserLogout pages,
  * and as a side effect makes redirects after login/logout more predictable.
  *
  * @link http://www.mediawiki.org/wiki/Manual:Hooks/PersonalUrls
  *
  * @param &$personal_urls array the array of URLs set up so far
  * @param Title $title the Title object of the current article
  *
  * @return boolean|string true on success, false on silent error, string on verbose error
  */
 public static function hookPersonalUrls(array &$personal_urls, Title $title)
 {
     if (!self::init()) {
         return true;
     }
     global $wgSamlRequirement;
     global $wgSamlPostLogoutRedirect;
     global $wgRequest;
     if ($wgSamlRequirement >= SAML_LOGIN_ONLY || self::$as->isAuthenticated()) {
         if (isset($personal_urls['logout'])) {
             if (isset($wgSamlPostLogoutRedirect)) {
                 $personal_urls['logout']['href'] = self::$as->getLogoutURL($wgSamlPostLogoutRedirect);
             } elseif ($wgSamlRequirement >= SAML_REQUIRED) {
                 $personal_urls['logout']['href'] = self::$as->getLogoutURL(self::$as->getLoginURL(Title::newMainPage()->getFullUrl()));
             } else {
                 $personal_urls['logout']['href'] = self::$as->getLogoutURL($personal_urls['logout']['href']);
             }
         }
         if (!self::$as->isAuthenticated()) {
             foreach (array('login', 'anonlogin') as $link) {
                 if (isset($personal_urls[$link])) {
                     if ($returnTo = $wgRequest->getVal('returnto') && ($page = Title::newFromText($returnTo))) {
                         $url = $page->getFullUrl();
                         $personal_urls[$link]['href'] = self::$as->getLoginURL($url);
                     } elseif ($title->isSpecial('Userlogout')) {
                         $personal_urls[$link]['href'] = self::$as->getLoginURL(Title::newMainPage()->getFullUrl());
                     } else {
                         $personal_urls[$link]['href'] = self::$as->getLoginURL();
                     }
                 }
             }
         }
     }
     return true;
 }
 /**
  * Check if we should redirect back to the specified page by comparing it to this black list
  * @param Title|null $title
  * @return bool
  */
 private function isInvalidRedirectOnConnect(Title $title = null)
 {
     return !$title instanceof Title || $title->isSpecial('Userlogout') || $title->isSpecial('Signup') || $title->isSpecial('UserLogin');
 }
 /**
  * @param $html string
  * @return string
  */
 public function DOMParse($html)
 {
     global $wgScript;
     wfProfileIn(__METHOD__);
     $html = mb_convert_encoding($html, 'HTML-ENTITIES', "UTF-8");
     libxml_use_internal_errors(true);
     $this->doc = new DOMDocument();
     $this->doc->loadHTML('<?xml encoding="UTF-8">' . $html);
     libxml_use_internal_errors(false);
     $this->doc->preserveWhiteSpace = false;
     $this->doc->strictErrorChecking = false;
     $this->doc->encoding = 'UTF-8';
     $itemToRemoveRecords = $this->parseItemsToRemove();
     $zeroRatedBannerElement = $this->doc->getElementById('zero-rated-banner');
     if (!$zeroRatedBannerElement) {
         $zeroRatedBannerElement = $this->doc->getElementById('zero-rated-banner-red');
     }
     if ($zeroRatedBannerElement) {
         self::$zeroRatedBanner = $this->doc->saveXML($zeroRatedBannerElement, LIBXML_NOEMPTYTAG);
     }
     if (self::$isBetaGroupMember) {
         $ptLogout = $this->doc->getElementById('pt-logout');
         if ($ptLogout) {
             $ptLogoutLink = $ptLogout->firstChild;
             self::$logoutHtml = $this->doc->saveXML($ptLogoutLink, LIBXML_NOEMPTYTAG);
         }
         $ptAnonLogin = $this->doc->getElementById('pt-anonlogin');
         if (!$ptAnonLogin) {
             $ptAnonLogin = $this->doc->getElementById('pt-login');
         }
         if ($ptAnonLogin) {
             $ptAnonLoginLink = $ptAnonLogin->firstChild;
             if ($ptAnonLoginLink && $ptAnonLoginLink->hasAttributes()) {
                 $ptAnonLoginLinkHref = $ptAnonLoginLink->getAttributeNode('href');
                 $ptAnonLoginLinkTitle = $ptAnonLoginLink->getAttributeNode('title');
                 if ($ptAnonLoginLinkTitle) {
                     $ptAnonLoginLinkTitle->nodeValue = self::$messages['mobile-frontend-login'];
                 }
                 if ($ptAnonLoginLinkHref) {
                     $ptAnonLoginLinkHref->nodeValue = str_replace("&", "&amp;", $ptAnonLoginLinkHref->nodeValue);
                 }
                 $ptAnonLoginLinkText = $ptAnonLoginLink->firstChild;
                 if ($ptAnonLoginLinkText) {
                     $ptAnonLoginLinkText->nodeValue = self::$messages['mobile-frontend-login'];
                 }
             }
             self::$loginHtml = $this->doc->saveXML($ptAnonLoginLink, LIBXML_NOEMPTYTAG);
         }
     }
     if (self::$title->isSpecial('Userlogin') && self::$isBetaGroupMember) {
         $userlogin = $this->doc->getElementById('userloginForm');
         if ($userlogin && get_class($userlogin) === 'DOMElement') {
             $firstHeading = $this->doc->getElementById('firstHeading');
             if ($firstHeading) {
                 $firstHeading->nodeValue = '';
             }
         }
     }
     // Tags
     // You can't remove DOMNodes from a DOMNodeList as you're iterating
     // over them in a foreach loop. It will seemingly leave the internal
     // iterator on the foreach out of wack and results will be quite
     // strange. Though, making a queue of items to remove seems to work.
     // For example:
     if (self::$disableImages == 1) {
         $itemToRemoveRecords['TAG'][] = "img";
         $itemToRemoveRecords['TAG'][] = "audio";
         $itemToRemoveRecords['TAG'][] = "video";
         $itemToRemoveRecords['CLASS'][] = "thumb tright";
         $itemToRemoveRecords['CLASS'][] = "thumb tleft";
         $itemToRemoveRecords['CLASS'][] = "thumbcaption";
         $itemToRemoveRecords['CLASS'][] = "gallery";
     }
     $tagToRemoveNodeIdAttributeValues = array('zero-language-search');
     $domElemsToRemove = array();
     foreach ($itemToRemoveRecords['TAG'] as $tagToRemove) {
         $tagToRemoveNodes = $this->doc->getElementsByTagName($tagToRemove);
         foreach ($tagToRemoveNodes as $tagToRemoveNode) {
             $tagToRemoveNodeIdAttributeValue = '';
             if ($tagToRemoveNode) {
                 $tagToRemoveNodeIdAttribute = $tagToRemoveNode->getAttributeNode('id');
                 if ($tagToRemoveNodeIdAttribute) {
                     $tagToRemoveNodeIdAttributeValue = $tagToRemoveNodeIdAttribute->value;
                 }
                 if (!in_array($tagToRemoveNodeIdAttributeValue, $tagToRemoveNodeIdAttributeValues)) {
                     $domElemsToRemove[] = $tagToRemoveNode;
                 }
             }
         }
     }
     foreach ($domElemsToRemove as $domElement) {
         $domElement->parentNode->removeChild($domElement);
     }
     // Elements with named IDs
     foreach ($itemToRemoveRecords['ID'] as $itemToRemove) {
         $itemToRemoveNode = $this->doc->getElementById($itemToRemove);
         if ($itemToRemoveNode) {
             $itemToRemoveNode->parentNode->removeChild($itemToRemoveNode);
         }
     }
     // CSS Classes
     $xpath = new DOMXpath($this->doc);
     foreach ($itemToRemoveRecords['CLASS'] as $classToRemove) {
         $elements = $xpath->query('//*[@class="' . $classToRemove . '"]');
         foreach ($elements as $element) {
             $element->parentNode->removeChild($element);
         }
     }
     // Tags with CSS Classes
     foreach ($itemToRemoveRecords['TAG_CLASS'] as $classToRemove) {
         $parts = explode('.', $classToRemove);
         $elements = $xpath->query('//' . $parts[0] . '[@class="' . $parts[1] . '"]');
         foreach ($elements as $element) {
             $removedElement = $element->parentNode->removeChild($element);
         }
     }
     // Handle red links with action equal to edit
     $redLinks = $xpath->query('//a[@class="new"]');
     foreach ($redLinks as $redLink) {
         // PHP Bug #36795 — Inappropriate "unterminated entity reference"
         $spanNode = $this->doc->createElement("span", str_replace("&", "&amp;", $redLink->nodeValue));
         if ($redLink->hasAttributes()) {
             $attributes = $redLink->attributes;
             foreach ($attributes as $i => $attribute) {
                 if ($attribute->name != 'href') {
                     $spanNode->setAttribute($attribute->name, $attribute->value);
                 }
             }
         }
         $redLink->parentNode->replaceChild($spanNode, $redLink);
     }
     if (self::$title->isSpecial('Userlogin') && self::$isBetaGroupMember) {
         if ($userlogin && get_class($userlogin) === 'DOMElement') {
             $login = $this->renderLogin();
             $loginNode = $this->doc->importNode($login, true);
             $userlogin->appendChild($loginNode);
         }
     }
     $content = $this->doc->getElementById('content');
     $contentHtml = $this->doc->saveXML($content, LIBXML_NOEMPTYTAG);
     if (self::$isMainPage) {
         $contentHtml = $this->DOMParseMainPage($contentHtml);
     }
     $title = htmlspecialchars(self::$title->getText());
     $htmlTitle = htmlspecialchars(self::$htmlTitle);
     if (strlen($contentHtml) > 4000 && $this->contentFormat == 'XHTML' && self::$device['supports_javascript'] === true && empty(self::$search) && !self::$isMainPage) {
         $contentHtml = $this->headingTransform($contentHtml);
     } elseif ($this->contentFormat == 'WML') {
         header('Content-Type: text/vnd.wap.wml');
         $contentHtml = $this->headingTransform($contentHtml);
         // Content removal for WML rendering
         $elements = array('span', 'div', 'sup', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'sup', 'sub');
         foreach ($elements as $element) {
             $contentHtml = preg_replace('#</?' . $element . '[^>]*>#is', '', $contentHtml);
         }
         // Wml for searching
         $searchWml = '<p><input emptyok="true" format="*M" type="text" name="search" value="" size="16" />' . '<do type="accept" label="' . self::$messages['mobile-frontend-search-submit'] . '">' . '<go href="' . $wgScript . '?title=Special%3ASearch&amp;search=$(search)"></go></do></p>';
         $contentHtml = $searchWml . $contentHtml;
         // Content wrapping
         $contentHtml = $this->createWMLCard($contentHtml);
         $applicationWmlTemplate = new ApplicationWmlTemplate();
         $options = array('mainPageUrl' => self::$mainPageUrl, 'randomPageUrl' => self::$randomPageUrl, 'dir' => self::$dir, 'code' => self::$code, 'contentHtml' => $contentHtml, 'homeButton' => self::$messages['mobile-frontend-home-button'], 'randomButton' => self::$messages['mobile-frontend-random-button']);
         $applicationWmlTemplate->setByArray($options);
         $applicationHtml = $applicationWmlTemplate->getHTML();
     }
     if ($this->contentFormat == 'XHTML' && self::$format != 'json') {
         if (!empty(self::$displayNoticeId)) {
             if (intval(self::$displayNoticeId) === 1) {
                 $thanksNoticeTemplate = new ThanksNoticeTemplate();
                 $thanksNoticeTemplate->set('messages', self::$messages);
                 $noticeHtml = $thanksNoticeTemplate->getHTML();
             }
         }
         // header( 'Content-Type: application/xhtml+xml; charset=utf-8' );
         $searchTemplate = $this->getSearchTemplate();
         $searchWebkitHtml = $searchTemplate->getHTML();
         $footerTemplate = $this->getFooterTemplate();
         $footerHtml = $footerTemplate->getHTML();
         $noticeHtml = !empty($noticeHtml) ? $noticeHtml : '';
         $applicationTemplate = $this->getApplicationTemplate();
         $options = array('noticeHtml' => $noticeHtml, 'htmlTitle' => $htmlTitle, 'searchWebkitHtml' => $searchWebkitHtml, 'contentHtml' => $contentHtml, 'footerHtml' => $footerHtml);
         $applicationTemplate->setByArray($options);
         $applicationHtml = $applicationTemplate->getHTML();
     }
     if (self::$format === 'json') {
         header('Content-Type: application/javascript');
         header('Content-Disposition: attachment; filename="data.js";');
         $json_data = array();
         $json_data['title'] = htmlspecialchars(self::$title->getText());
         $json_data['html'] = $contentHtml;
         $json = FormatJson::encode($json_data);
         if (!empty(self::$callback)) {
             $json = urlencode(htmlspecialchars(self::$callback)) . '(' . $json . ')';
         }
         wfProfileOut(__METHOD__);
         return $json;
     }
     wfProfileOut(__METHOD__);
     return $applicationHtml;
 }
 /**
  * This hook is called when about to force a redirect to a canonical URL
  * for a title when we have no other parameters on the URL.
  *
  * Return false when we want to prevent the redirect to the canonical URL
  * for Our404Handler special page
  *
  * @see PLATFORM-811
  *
  * @param WebRequest $request
  * @param Title $title
  * @param OutputPage $output
  * @return bool
  */
 public static function onTestCanonicalRedirect(WebRequest $request, Title $title, OutputPage $output)
 {
     if ($title->isSpecial(self::NAME)) {
         return false;
     }
     return true;
 }
 function isIgnoredPage(Title $title)
 {
     global $wgGoogleUniversalAnalyticsIgnoreNsIDs, $wgGoogleUniversalAnalyticsIgnorePages, $wgGoogleUniversalAnalyticsIgnoreSpecials;
     $ignoreSpecials = count(array_filter($wgGoogleUniversalAnalyticsIgnoreSpecials, function ($v) use($title) {
         return $title->isSpecial($v);
     })) > 0;
     return $ignoreSpecials || in_array($title->getNamespace(), $wgGoogleUniversalAnalyticsIgnoreNsIDs, true) || in_array($title->getPrefixedText(), $wgGoogleUniversalAnalyticsIgnorePages, true);
 }
 static function isSpecialGoogleSearch(Title $title)
 {
     return $title->isSpecial('WRGoogleSearch');
 }