/**
  * Execute a special page path.
  * The path may contain parameters, e.g. Special:Name/Params
  * Extracts the special page name and call the execute method, passing the parameters
  *
  * Returns a title object if the page is redirected, false if there was no such special
  * page, and true if it was successful.
  *
  * @param Title $title
  * @param IContextSource $context
  * @param bool $including Bool output is being captured for use in {{special:whatever}}
  *
  * @return bool
  */
 public static function executePath(Title &$title, IContextSource &$context, $including = false)
 {
     // @todo FIXME: Redirects broken due to this call
     $bits = explode('/', $title->getDBkey(), 2);
     $name = $bits[0];
     if (!isset($bits[1])) {
         // bug 2087
         $par = null;
     } else {
         $par = $bits[1];
     }
     $page = self::getPage($name);
     if (!$page) {
         $context->getOutput()->setArticleRelated(false);
         $context->getOutput()->setRobotPolicy('noindex,nofollow');
         global $wgSend404Code;
         if ($wgSend404Code) {
             $context->getOutput()->setStatusCode(404);
         }
         $context->getOutput()->showErrorPage('nosuchspecialpage', 'nospecialpagetext');
         return false;
     }
     if (!$including) {
         // Narrow DB query expectations for this HTTP request
         $trxLimits = $context->getConfig()->get('TrxProfilerLimits');
         $trxProfiler = Profiler::instance()->getTransactionProfiler();
         if ($context->getRequest()->wasPosted() && !$page->doesWrites()) {
             $trxProfiler->setExpectations($trxLimits['POST-nonwrite'], __METHOD__);
             $context->getRequest()->markAsSafeRequest();
         }
     }
     // Page exists, set the context
     $page->setContext($context);
     if (!$including) {
         // Redirect to canonical alias for GET commands
         // Not for POST, we'd lose the post data, so it's best to just distribute
         // the request. Such POST requests are possible for old extensions that
         // generate self-links without being aware that their default name has
         // changed.
         if ($name != $page->getLocalName() && !$context->getRequest()->wasPosted()) {
             $query = $context->getRequest()->getQueryValues();
             unset($query['title']);
             $title = $page->getPageTitle($par);
             $url = $title->getFullURL($query);
             $context->getOutput()->redirect($url);
             return $title;
         } else {
             $context->setTitle($page->getPageTitle($par));
         }
     } elseif (!$page->isIncludable()) {
         return false;
     }
     $page->including($including);
     // Execute special page
     $page->run($par);
     return true;
 }
示例#2
0
文件: ApiHelp.php 项目: paladox/2
 /**
  * Generate help for the specified modules
  *
  * Help is placed into the OutputPage object returned by
  * $context->getOutput().
  *
  * Recognized options include:
  *  - headerlevel: (int) Header tag level
  *  - nolead: (bool) Skip the inclusion of api-help-lead
  *  - noheader: (bool) Skip the inclusion of the top-level section headers
  *  - submodules: (bool) Include help for submodules of the current module
  *  - recursivesubmodules: (bool) Include help for submodules recursively
  *  - helptitle: (string) Title to link for additional modules' help. Should contain $1.
  *  - toc: (bool) Include a table of contents
  *
  * @param IContextSource $context
  * @param ApiBase[]|ApiBase $modules
  * @param array $options Formatting options (described above)
  * @return string
  */
 public static function getHelp(IContextSource $context, $modules, array $options)
 {
     global $wgContLang;
     if (!is_array($modules)) {
         $modules = array($modules);
     }
     $out = $context->getOutput();
     $out->addModuleStyles('mediawiki.hlist');
     $out->addModuleStyles('mediawiki.apihelp');
     if (!empty($options['toc'])) {
         $out->addModules('mediawiki.toc');
     }
     $out->setPageTitle($context->msg('api-help-title'));
     $cache = ObjectCache::getMainWANInstance();
     $cacheKey = null;
     if (count($modules) == 1 && $modules[0] instanceof ApiMain && $options['recursivesubmodules'] && $context->getLanguage() === $wgContLang) {
         $cacheHelpTimeout = $context->getConfig()->get('APICacheHelpTimeout');
         if ($cacheHelpTimeout > 0) {
             // Get help text from cache if present
             $cacheKey = wfMemcKey('apihelp', $modules[0]->getModulePath(), (int) (!empty($options['toc'])), str_replace(' ', '_', SpecialVersion::getVersion('nodb')));
             $cached = $cache->get($cacheKey);
             if ($cached) {
                 $out->addHTML($cached);
                 return;
             }
         }
     }
     if ($out->getHTML() !== '') {
         // Don't save to cache, there's someone else's content in the page
         // already
         $cacheKey = null;
     }
     $options['recursivesubmodules'] = !empty($options['recursivesubmodules']);
     $options['submodules'] = $options['recursivesubmodules'] || !empty($options['submodules']);
     // Prepend lead
     if (empty($options['nolead'])) {
         $msg = $context->msg('api-help-lead');
         if (!$msg->isDisabled()) {
             $out->addHTML($msg->parseAsBlock());
         }
     }
     $haveModules = array();
     $html = self::getHelpInternal($context, $modules, $options, $haveModules);
     if (!empty($options['toc']) && $haveModules) {
         $out->addHTML(Linker::generateTOC($haveModules, $context->getLanguage()));
     }
     $out->addHTML($html);
     $helptitle = isset($options['helptitle']) ? $options['helptitle'] : null;
     $html = self::fixHelpLinks($out->getHTML(), $helptitle, $haveModules);
     $out->clearHTML();
     $out->addHTML($html);
     if ($cacheKey !== null) {
         $cache->set($cacheKey, $out->getHTML(), $cacheHelpTimeout);
     }
 }
示例#3
0
 /**
  * @param IContextSource $context
  * @return array
  */
 static function getTimezoneOptions(IContextSource $context)
 {
     $opt = array();
     $localTZoffset = $context->getConfig()->get('LocalTZoffset');
     $timeZoneList = self::getTimeZoneList($context->getLanguage());
     $timestamp = MWTimestamp::getLocalInstance();
     // Check that the LocalTZoffset is the same as the local time zone offset
     if ($localTZoffset == $timestamp->format('Z') / 60) {
         $timezoneName = $timestamp->getTimezone()->getName();
         // Localize timezone
         if (isset($timeZoneList[$timezoneName])) {
             $timezoneName = $timeZoneList[$timezoneName]['name'];
         }
         $server_tz_msg = $context->msg('timezoneuseserverdefault', $timezoneName)->text();
     } else {
         $tzstring = sprintf('%+03d:%02d', floor($localTZoffset / 60), abs($localTZoffset) % 60);
         $server_tz_msg = $context->msg('timezoneuseserverdefault', $tzstring)->text();
     }
     $opt[$server_tz_msg] = "System|{$localTZoffset}";
     $opt[$context->msg('timezoneuseoffset')->text()] = 'other';
     $opt[$context->msg('guesstimezone')->text()] = 'guess';
     foreach ($timeZoneList as $timeZoneInfo) {
         $region = $timeZoneInfo['region'];
         if (!isset($opt[$region])) {
             $opt[$region] = array();
         }
         $opt[$region][$timeZoneInfo['name']] = $timeZoneInfo['timecorrection'];
     }
     return $opt;
 }
示例#4
0
 /**
  * Really send a mail. Permissions should have been checked using
  * getPermissionsError(). It is probably also a good
  * idea to check the edit token and ping limiter in advance.
  *
  * @param array $data
  * @param IContextSource $context
  * @return Status|string|bool Status object, or potentially a String on error
  * or maybe even true on success if anything uses the EmailUser hook.
  */
 public static function submit(array $data, IContextSource $context)
 {
     $config = $context->getConfig();
     $target = self::getTarget($data['Target']);
     if (!$target instanceof User) {
         // Messages used here: notargettext, noemailtext, nowikiemailtext
         return $context->msg($target . 'text')->parseAsBlock();
     }
     $to = MailAddress::newFromUser($target);
     $from = MailAddress::newFromUser($context->getUser());
     $subject = $data['Subject'];
     $text = $data['Text'];
     // Add a standard footer and trim up trailing newlines
     $text = rtrim($text) . "\n\n-- \n";
     $text .= $context->msg('emailuserfooter', $from->name, $to->name)->inContentLanguage()->text();
     $error = '';
     if (!Hooks::run('EmailUser', array(&$to, &$from, &$subject, &$text, &$error))) {
         return $error;
     }
     if ($config->get('UserEmailUseReplyTo')) {
         /**
          * Put the generic wiki autogenerated address in the From:
          * header and reserve the user for Reply-To.
          *
          * This is a bit ugly, but will serve to differentiate
          * wiki-borne mails from direct mails and protects against
          * SPF and bounce problems with some mailers (see below).
          */
         $mailFrom = new MailAddress($config->get('PasswordSender'), wfMessage('emailsender')->inContentLanguage()->text());
         $replyTo = $from;
     } else {
         /**
          * Put the sending user's e-mail address in the From: header.
          *
          * This is clean-looking and convenient, but has issues.
          * One is that it doesn't as clearly differentiate the wiki mail
          * from "directly" sent mails.
          *
          * Another is that some mailers (like sSMTP) will use the From
          * address as the envelope sender as well. For open sites this
          * can cause mails to be flunked for SPF violations (since the
          * wiki server isn't an authorized sender for various users'
          * domains) as well as creating a privacy issue as bounces
          * containing the recipient's e-mail address may get sent to
          * the sending user.
          */
         $mailFrom = $from;
         $replyTo = null;
     }
     $status = UserMailer::send($to, $mailFrom, $subject, $text, array('replyTo' => $replyTo));
     if (!$status->isGood()) {
         return $status;
     } else {
         // if the user requested a copy of this mail, do this now,
         // unless they are emailing themselves, in which case one
         // copy of the message is sufficient.
         if ($data['CCMe'] && $to != $from) {
             $cc_subject = $context->msg('emailccsubject')->rawParams($target->getName(), $subject)->text();
             // target and sender are equal, because this is the CC for the sender
             Hooks::run('EmailUserCC', array(&$from, &$from, &$cc_subject, &$text));
             $ccStatus = UserMailer::send($from, $from, $cc_subject, $text);
             $status->merge($ccStatus);
         }
         Hooks::run('EmailUserComplete', array($to, $from, $subject, $text));
         return $status;
     }
 }
示例#5
0
 /**
  * This function commits all DB changes as needed before
  * the user can receive a response (in case commit fails)
  *
  * @param IContextSource $context
  * @since 1.27
  */
 public static function preOutputCommit(IContextSource $context)
 {
     // Either all DBs should commit or none
     ignore_user_abort(true);
     $config = $context->getConfig();
     $factory = wfGetLBFactory();
     // Check if any transaction was too big
     $limit = $config->get('MaxUserDBWriteDuration');
     $factory->forEachLB(function (LoadBalancer $lb) use($limit) {
         $lb->forEachOpenConnection(function (IDatabase $db) use($limit) {
             $time = $db->pendingWriteQueryDuration();
             if ($limit > 0 && $time > $limit) {
                 throw new DBTransactionError($db, wfMessage('transaction-duration-limit-exceeded', $time, $limit)->text());
             }
         });
     });
     // Commit all changes
     $factory->commitMasterChanges(__METHOD__);
     // Record ChronologyProtector positions
     $factory->shutdown();
     wfDebug(__METHOD__ . ': all transactions committed');
     DeferredUpdates::doUpdates('enqueue', DeferredUpdates::PRESEND);
     wfDebug(__METHOD__ . ': pre-send deferred updates completed');
     // Set a cookie to tell all CDN edge nodes to "stick" the user to the
     // DC that handles this POST request (e.g. the "master" data center)
     $request = $context->getRequest();
     if ($request->wasPosted() && $factory->hasOrMadeRecentMasterChanges()) {
         $expires = time() + $config->get('DataCenterUpdateStickTTL');
         $request->response()->setCookie('UseDC', 'master', $expires, array('prefix' => ''));
     }
     // Avoid letting a few seconds of slave lag cause a month of stale data
     if ($factory->laggedSlaveUsed()) {
         $maxAge = $config->get('CdnMaxageLagged');
         $context->getOutput()->lowerCdnMaxage($maxAge);
         $request->response()->header("X-Database-Lagged: true");
         wfDebugLog('replication', "Lagged DB used; CDN cache TTL limited to {$maxAge} seconds");
     }
 }
示例#6
0
 /**
  * @param string $url
  * @param IContextSource $context
  * @return string|bool Either "local" or "remote" if in the farm, false otherwise
  */
 private static function getUrlDomainDistance($url, IContextSource $context)
 {
     static $relevantKeys = ['host' => true, 'port' => true];
     $infoCandidate = wfParseUrl($url);
     if ($infoCandidate === false) {
         return false;
     }
     $infoCandidate = array_intersect_key($infoCandidate, $relevantKeys);
     $clusterHosts = array_merge([$context->getConfig()->get('CanonicalServer')], $context->getConfig()->get('LocalVirtualHosts'));
     foreach ($clusterHosts as $i => $clusterHost) {
         $parseUrl = wfParseUrl($clusterHost);
         if (!$parseUrl) {
             continue;
         }
         $infoHost = array_intersect_key($parseUrl, $relevantKeys);
         if ($infoCandidate === $infoHost) {
             return $i === 0 ? 'local' : 'remote';
         }
     }
     return false;
 }
    /**
     * Build the input form
     *
     * @return string HTML form
     */
    function buildForm()
    {
        $user = $this->mContext->getUser();
        $output = $this->mContext->getOutput();
        $lang = $this->mContext->getLanguage();
        $cascadingRestrictionLevels = $this->mContext->getConfig()->get('CascadingRestrictionLevels');
        $out = '';
        if (!$this->disabled) {
            $output->addModules('mediawiki.legacy.protect');
            $output->addJsConfigVars('wgCascadeableLevels', $cascadingRestrictionLevels);
            $out .= Xml::openElement('form', array('method' => 'post', 'action' => $this->mTitle->getLocalURL('action=protect'), 'id' => 'mw-Protect-Form'));
        }
        $out .= Xml::openElement('fieldset') . Xml::element('legend', null, wfMessage('protect-legend')->text()) . Xml::openElement('table', array('id' => 'mwProtectSet')) . Xml::openElement('tbody');
        $scExpiryOptions = wfMessage('protect-expiry-options')->inContentLanguage()->text();
        $showProtectOptions = $scExpiryOptions !== '-' && !$this->disabled;
        // Not all languages have V_x <-> N_x relation
        foreach ($this->mRestrictions as $action => $selected) {
            // Messages:
            // restriction-edit, restriction-move, restriction-create, restriction-upload
            $msg = wfMessage('restriction-' . $action);
            $out .= "<tr><td>" . Xml::openElement('fieldset') . Xml::element('legend', null, $msg->exists() ? $msg->text() : $action) . Xml::openElement('table', array('id' => "mw-protect-table-{$action}")) . "<tr><td>" . $this->buildSelector($action, $selected) . "</td></tr><tr><td>";
            $mProtectexpiry = Xml::label(wfMessage('protectexpiry')->text(), "mwProtectExpirySelection-{$action}");
            $mProtectother = Xml::label(wfMessage('protect-othertime')->text(), "mwProtect-{$action}-expires");
            $expiryFormOptions = '';
            if ($this->mExistingExpiry[$action] && $this->mExistingExpiry[$action] != 'infinity') {
                $timestamp = $lang->timeanddate($this->mExistingExpiry[$action], true);
                $d = $lang->date($this->mExistingExpiry[$action], true);
                $t = $lang->time($this->mExistingExpiry[$action], true);
                $expiryFormOptions .= Xml::option(wfMessage('protect-existing-expiry', $timestamp, $d, $t)->text(), 'existing', $this->mExpirySelection[$action] == 'existing') . "\n";
            }
            $expiryFormOptions .= Xml::option(wfMessage('protect-othertime-op')->text(), "othertime") . "\n";
            foreach (explode(',', $scExpiryOptions) as $option) {
                if (strpos($option, ":") === false) {
                    $show = $value = $option;
                } else {
                    list($show, $value) = explode(":", $option);
                }
                $show = htmlspecialchars($show);
                $value = htmlspecialchars($value);
                $expiryFormOptions .= Xml::option($show, $value, $this->mExpirySelection[$action] === $value) . "\n";
            }
            # Add expiry dropdown
            if ($showProtectOptions && !$this->disabled) {
                $out .= "\n\t\t\t\t\t<table><tr>\n\t\t\t\t\t\t<td class='mw-label'>\n\t\t\t\t\t\t\t{$mProtectexpiry}\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td class='mw-input'>" . Xml::tags('select', array('id' => "mwProtectExpirySelection-{$action}", 'name' => "wpProtectExpirySelection-{$action}", 'tabindex' => '2') + $this->disabledAttrib, $expiryFormOptions) . "</td>\n\t\t\t\t\t</tr></table>";
            }
            # Add custom expiry field
            $attribs = array('id' => "mwProtect-{$action}-expires") + $this->disabledAttrib;
            $out .= "<table><tr>\n\t\t\t\t\t<td class='mw-label'>" . $mProtectother . '</td>
					<td class="mw-input">' . Xml::input("mwProtect-expiry-{$action}", 50, $this->mExpiry[$action], $attribs) . '</td>
				</tr></table>';
            $out .= "</td></tr>" . Xml::closeElement('table') . Xml::closeElement('fieldset') . "</td></tr>";
        }
        # Give extensions a chance to add items to the form
        wfRunHooks('ProtectionForm::buildForm', array($this->mArticle, &$out));
        $out .= Xml::closeElement('tbody') . Xml::closeElement('table');
        // JavaScript will add another row with a value-chaining checkbox
        if ($this->mTitle->exists()) {
            $out .= Xml::openElement('table', array('id' => 'mw-protect-table2')) . Xml::openElement('tbody');
            $out .= '<tr>
					<td></td>
					<td class="mw-input">' . Xml::checkLabel(wfMessage('protect-cascade')->text(), 'mwProtect-cascade', 'mwProtect-cascade', $this->mCascade, $this->disabledAttrib) . "</td>\n\t\t\t\t</tr>\n";
            $out .= Xml::closeElement('tbody') . Xml::closeElement('table');
        }
        # Add manual and custom reason field/selects as well as submit
        if (!$this->disabled) {
            $mProtectreasonother = Xml::label(wfMessage('protectcomment')->text(), 'wpProtectReasonSelection');
            $mProtectreason = Xml::label(wfMessage('protect-otherreason')->text(), 'mwProtect-reason');
            $reasonDropDown = Xml::listDropDown('wpProtectReasonSelection', wfMessage('protect-dropdown')->inContentLanguage()->text(), wfMessage('protect-otherreason-op')->inContentLanguage()->text(), $this->mReasonSelection, 'mwProtect-reason', 4);
            $out .= Xml::openElement('table', array('id' => 'mw-protect-table3')) . Xml::openElement('tbody');
            $out .= "\n\t\t\t\t<tr>\n\t\t\t\t\t<td class='mw-label'>\n\t\t\t\t\t\t{$mProtectreasonother}\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class='mw-input'>\n\t\t\t\t\t\t{$reasonDropDown}\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td class='mw-label'>\n\t\t\t\t\t\t{$mProtectreason}\n\t\t\t\t\t</td>\n\t\t\t\t\t<td class='mw-input'>" . Xml::input('mwProtect-reason', 60, $this->mReason, array('type' => 'text', 'id' => 'mwProtect-reason', 'maxlength' => 180)) . "</td>\n\t\t\t\t</tr>";
            # Disallow watching is user is not logged in
            if ($user->isLoggedIn()) {
                $out .= "\n\t\t\t\t<tr>\n\t\t\t\t\t<td></td>\n\t\t\t\t\t<td class='mw-input'>" . Xml::checkLabel(wfMessage('watchthis')->text(), 'mwProtectWatch', 'mwProtectWatch', $user->isWatched($this->mTitle) || $user->getOption('watchdefault')) . "</td>\n\t\t\t\t</tr>";
            }
            $out .= "\n\t\t\t\t<tr>\n\t\t\t\t\t<td></td>\n\t\t\t\t\t<td class='mw-submit'>" . Xml::submitButton(wfMessage('confirm')->text(), array('id' => 'mw-Protect-submit')) . "</td>\n\t\t\t\t</tr>\n";
            $out .= Xml::closeElement('tbody') . Xml::closeElement('table');
        }
        $out .= Xml::closeElement('fieldset');
        if ($user->isAllowed('editinterface')) {
            $title = Title::makeTitle(NS_MEDIAWIKI, 'Protect-dropdown');
            $link = Linker::link($title, wfMessage('protect-edit-reasonlist')->escaped(), array(), array('action' => 'edit'));
            $out .= '<p class="mw-protect-editreasons">' . $link . '</p>';
        }
        if (!$this->disabled) {
            $out .= Html::hidden('wpEditToken', $user->getEditToken(array('protect', $this->mTitle->getPrefixedDBkey())));
            $out .= Xml::closeElement('form');
        }
        return $out;
    }
 /**
  * Return the legend displayed within the fieldset
  * @todo This should not be static, then we can drop the parameter
  * @todo Not called by anything, should be called by doHeader()
  *
  * @param IContextSource $context The object available as $this in non-static functions
  * @return string
  */
 public static function makeLegend(IContextSource $context)
 {
     $user = $context->getUser();
     # The legend showing what the letters and stuff mean
     $legend = Html::openElement('dl') . "\n";
     # Iterates through them and gets the messages for both letter and tooltip
     $legendItems = $context->getConfig()->get('RecentChangesFlags');
     if (!($user->useRCPatrol() || $user->useNPPatrol())) {
         unset($legendItems['unpatrolled']);
     }
     foreach ($legendItems as $key => $item) {
         # generate items of the legend
         $label = isset($item['legend']) ? $item['legend'] : $item['title'];
         $letter = $item['letter'];
         $cssClass = isset($item['class']) ? $item['class'] : $key;
         $legend .= Html::element('dt', array('class' => $cssClass), $context->msg($letter)->text()) . "\n" . Html::rawElement('dd', array(), $context->msg($label)->parse()) . "\n";
     }
     # (+-123)
     $legend .= Html::rawElement('dt', array('class' => 'mw-plusminus-pos'), $context->msg('recentchanges-legend-plusminus')->parse()) . "\n";
     $legend .= Html::element('dd', array('class' => 'mw-changeslist-legend-plusminus'), $context->msg('recentchanges-label-plusminus')->text()) . "\n";
     $legend .= Html::closeElement('dl') . "\n";
     # Collapsibility
     $legend = '<div class="mw-changeslist-legend">' . $context->msg('recentchanges-legend-heading')->parse() . '<div class="mw-collapsible-content">' . $legend . '</div>' . '</div>';
     return $legend;
 }
 /**
  * @param IContextSource $context
  * @return array
  */
 static function getTimezoneOptions(IContextSource $context)
 {
     $opt = array();
     $localTZoffset = $context->getConfig()->get('LocalTZoffset');
     $timestamp = MWTimestamp::getLocalInstance();
     // Check that the LocalTZoffset is the same as the local time zone offset
     if ($localTZoffset == $timestamp->format('Z') / 60) {
         $server_tz_msg = $context->msg('timezoneuseserverdefault', $timestamp->getTimezone()->getName())->text();
     } else {
         $tzstring = sprintf('%+03d:%02d', floor($localTZoffset / 60), abs($localTZoffset) % 60);
         $server_tz_msg = $context->msg('timezoneuseserverdefault', $tzstring)->text();
     }
     $opt[$server_tz_msg] = "System|{$localTZoffset}";
     $opt[$context->msg('timezoneuseoffset')->text()] = 'other';
     $opt[$context->msg('guesstimezone')->text()] = 'guess';
     if (function_exists('timezone_identifiers_list')) {
         # Read timezone list
         $tzs = timezone_identifiers_list();
         sort($tzs);
         $tzRegions = array();
         $tzRegions['Africa'] = $context->msg('timezoneregion-africa')->text();
         $tzRegions['America'] = $context->msg('timezoneregion-america')->text();
         $tzRegions['Antarctica'] = $context->msg('timezoneregion-antarctica')->text();
         $tzRegions['Arctic'] = $context->msg('timezoneregion-arctic')->text();
         $tzRegions['Asia'] = $context->msg('timezoneregion-asia')->text();
         $tzRegions['Atlantic'] = $context->msg('timezoneregion-atlantic')->text();
         $tzRegions['Australia'] = $context->msg('timezoneregion-australia')->text();
         $tzRegions['Europe'] = $context->msg('timezoneregion-europe')->text();
         $tzRegions['Indian'] = $context->msg('timezoneregion-indian')->text();
         $tzRegions['Pacific'] = $context->msg('timezoneregion-pacific')->text();
         asort($tzRegions);
         $prefill = array_fill_keys(array_values($tzRegions), array());
         $opt = array_merge($opt, $prefill);
         $now = date_create('now');
         foreach ($tzs as $tz) {
             $z = explode('/', $tz, 2);
             # timezone_identifiers_list() returns a number of
             # backwards-compatibility entries. This filters them out of the
             # list presented to the user.
             if (count($z) != 2 || !array_key_exists($z[0], $tzRegions)) {
                 continue;
             }
             # Localize region
             $z[0] = $tzRegions[$z[0]];
             $minDiff = floor(timezone_offset_get(timezone_open($tz), $now) / 60);
             $display = str_replace('_', ' ', $z[0] . '/' . $z[1]);
             $value = "ZoneInfo|{$minDiff}|{$tz}";
             $opt[$z[0]][$display] = $value;
         }
     }
     return $opt;
 }
示例#10
0
 /**
  * This function commits all DB changes as needed before
  * the user can receive a response (in case commit fails)
  *
  * @param IContextSource $context
  * @since 1.27
  */
 public static function preOutputCommit(IContextSource $context)
 {
     // Either all DBs should commit or none
     ignore_user_abort(true);
     $config = $context->getConfig();
     $factory = wfGetLBFactory();
     // Commit all changes
     $factory->commitMasterChanges(__METHOD__, array('maxWriteDuration' => $config->get('MaxUserDBWriteDuration')));
     // Record ChronologyProtector positions
     $factory->shutdown();
     wfDebug(__METHOD__ . ': all transactions committed');
     DeferredUpdates::doUpdates('enqueue', DeferredUpdates::PRESEND);
     wfDebug(__METHOD__ . ': pre-send deferred updates completed');
     // Set a cookie to tell all CDN edge nodes to "stick" the user to the DC that handles this
     // POST request (e.g. the "master" data center). Also have the user briefly bypass CDN so
     // ChronologyProtector works for cacheable URLs.
     $request = $context->getRequest();
     if ($request->wasPosted() && $factory->hasOrMadeRecentMasterChanges()) {
         $expires = time() + $config->get('DataCenterUpdateStickTTL');
         $options = array('prefix' => '');
         $request->response()->setCookie('UseDC', 'master', $expires, $options);
         $request->response()->setCookie('UseCDNCache', 'false', $expires, $options);
     }
     // Avoid letting a few seconds of slave lag cause a month of stale data. This logic is
     // also intimately related to the value of $wgCdnReboundPurgeDelay.
     if ($factory->laggedSlaveUsed()) {
         $maxAge = $config->get('CdnMaxageLagged');
         $context->getOutput()->lowerCdnMaxage($maxAge);
         $request->response()->header("X-Database-Lagged: true");
         wfDebugLog('replication', "Lagged DB used; CDN cache TTL limited to {$maxAge} seconds");
     }
 }
示例#11
0
 /**
  * This function commits all DB changes as needed before
  * the user can receive a response (in case commit fails)
  *
  * @param IContextSource $context
  * @since 1.27
  */
 public static function preOutputCommit(IContextSource $context)
 {
     // Either all DBs should commit or none
     ignore_user_abort(true);
     // Commit all changes and record ChronologyProtector positions
     $factory = wfGetLBFactory();
     $factory->commitMasterChanges();
     $factory->shutdown();
     wfDebug(__METHOD__ . ' completed; all transactions committed');
     // Set a cookie to tell all CDN edge nodes to "stick" the user to the
     // DC that handles this POST request (e.g. the "master" data center)
     $request = $context->getRequest();
     $config = $context->getConfig();
     if ($request->wasPosted() && $factory->hasOrMadeRecentMasterChanges()) {
         $expires = time() + $config->get('DataCenterUpdateStickTTL');
         $request->response()->setCookie('UseDC', 'master', $expires, array('prefix' => ''));
     }
     // Avoid letting a few seconds of slave lag cause a month of stale data
     if ($factory->laggedSlaveUsed()) {
         $maxAge = $config->get('CdnMaxageLagged');
         $context->getOutput()->lowerCdnMaxage($maxAge);
         $request->response()->header("X-Database-Lagged: true");
         wfDebugLog('replication', "Lagged DB used; CDN cache TTL limited to {$maxAge} seconds");
     }
 }