public function getVersion()
 {
     if ($this->version === self::INHERIT_VALUE) {
         return $this->context->getVersion();
     }
     return $this->version;
 }
 public function getVersion()
 {
     if (!is_null($this->version)) {
         return $this->version;
     } else {
         return $this->context->getVersion();
     }
 }
Пример #3
0
 /**
  * Helper for createLoaderURL()
  *
  * @since 1.24
  * @see makeLoaderQuery
  * @param ResourceLoaderContext $context
  * @param array $extraQuery
  * @return array
  */
 public static function createLoaderQuery(ResourceLoaderContext $context, $extraQuery = array())
 {
     return self::makeLoaderQuery($context->getModules(), $context->getLanguage(), $context->getSkin(), $context->getUser(), $context->getVersion(), $context->getDebug(), $context->getOnly(), $context->getRequest()->getBool('printable'), $context->getRequest()->getBool('handheld'), $extraQuery);
 }
Пример #4
0
 /**
  * Get the URL or URLs to load for this module's CSS in debug mode.
  * The default behavior is to return a load.php?only=styles URL for
  * the module, but file-based modules will want to override this to
  * load the files directly. See also getScriptURLsForDebug()
  *
  * @param $context ResourceLoaderContext: Context object
  * @return Array: array( mediaType => array( URL1, URL2, ... ), ... )
  */
 public function getStyleURLsForDebug(ResourceLoaderContext $context)
 {
     $url = ResourceLoader::makeLoaderURL(array($this->getName()), $context->getLanguage(), $context->getSkin(), $context->getUser(), $context->getVersion(), true, 'styles', $context->getRequest()->getBool('printable'), $context->getRequest()->getBool('handheld'));
     return array('all' => array($url));
 }
 /**
  * Get the load.php URL that will produce this image.
  *
  * @param ResourceLoaderContext $context Any context
  * @param string $script URL to load.php
  * @param string|null $variant Variant to get the URL for
  * @param string $format Format to get the URL for, 'original' or 'rasterized'
  * @return string
  */
 public function getUrl(ResourceLoaderContext $context, $script, $variant, $format)
 {
     $query = array('modules' => $this->getModule(), 'image' => $this->getName(), 'variant' => $variant, 'format' => $format, 'lang' => $context->getLanguage(), 'version' => $context->getVersion());
     return wfExpandUrl(wfAppendQuery($script, $query), PROTO_RELATIVE);
 }
Пример #6
0
 /**
  * Send out code for a response from file cache if possible
  *
  * @param $fileCache ResourceFileCache: Cache object for this request URL
  * @param $context ResourceLoaderContext: Context in which to generate a response
  * @return bool If this found a cache file and handled the response
  */
 protected function tryRespondFromFileCache(ResourceFileCache $fileCache, ResourceLoaderContext $context)
 {
     global $wgResourceLoaderMaxage;
     // Buffer output to catch warnings.
     ob_start();
     // Get the maximum age the cache can be
     $maxage = is_null($context->getVersion()) ? $wgResourceLoaderMaxage['unversioned']['server'] : $wgResourceLoaderMaxage['versioned']['server'];
     // Minimum timestamp the cache file must have
     $good = $fileCache->isCacheGood(wfTimestamp(TS_MW, time() - $maxage));
     if (!$good) {
         try {
             // RL always hits the DB on file cache miss...
             wfGetDB(DB_SLAVE);
         } catch (DBConnectionError $e) {
             // ...check if we need to fallback to cache
             $good = $fileCache->isCacheGood();
             // cache existence check
         }
     }
     if ($good) {
         $ts = $fileCache->cacheTimestamp();
         // Send content type and cache headers
         $this->sendResponseHeaders($context, $ts, false);
         // If there's an If-Modified-Since header, respond with a 304 appropriately
         if ($this->tryRespondLastModified($context, $ts)) {
             return false;
             // output handled (buffers cleared)
         }
         $response = $fileCache->fetchText();
         // Capture any PHP warnings from the output buffer and append them to the
         // response in a comment if we're in debug mode.
         if ($context->getDebug() && strlen($warnings = ob_get_contents())) {
             $response = "/*\n{$warnings}\n*/\n" . $response;
         }
         // Remove the output buffer and output the response
         ob_end_clean();
         echo $response . "\n/* Cached {$ts} */";
         return true;
         // cache hit
     }
     // Clear buffer
     ob_end_clean();
     return false;
     // cache miss
 }
 /**
  * Customize caching policy for RL modules
  *
  * * cache "static" modules for 30 days when cb param in the URL matches $wgStyleVersion
  * * cache "dynamic" modules for 30 days when version param is present in the URL and matches $mtime timestamp
  * * otherwise fallback to caching for 5 minutes
  *
  * @see BAC-1241
  *
  * @param ResourceLoader $rl
  * @param ResourceLoaderContext $context
  * @param $mtime int UNIX timestamp from module(s) calculated from filesystem
  * @param $maxage int UNIX timestamp for maxage
  * @param $smaxage int UNIX timestamp for smaxage
  * @return bool it's a hook
  */
 public static function onResourceLoaderModifyMaxAge(ResourceLoader $rl, ResourceLoaderContext $context, $mtime, &$maxage, &$smaxage)
 {
     global $wgStyleVersion, $wgResourceLoaderMaxage;
     // parse cb and version provided as URL parameters
     // version%3D123456-20140220T090000Z
     // cb%3D123456%26
     $version = explode('-', (string) $context->getVersion(), 2);
     if (count($version) === 2) {
         list($cb, $ts) = $version;
         $ts = strtotime($ts);
         // convert MW to UNIX timestamp
     } else {
         $cb = $context->getRequest()->getVal('cb', false);
         $ts = false;
     }
     // check if at least one of required modules serves dynamic content
     $hasDynamicModule = false;
     $modules = $context->getModules();
     foreach ($modules as $moduleName) {
         if (!$rl->getModule($moduleName) instanceof ResourceLoaderFileModule) {
             $hasDynamicModule = true;
             break;
         }
     }
     if ($hasDynamicModule) {
         // use long TTL when version value matches $mtime passed to the hook
         $useLongTTL = !empty($ts) && $ts <= $mtime;
     } else {
         // use long TTL when cache buster value from URL matches $wgStyleVersion
         $useLongTTL = !empty($cb) && $cb <= $wgStyleVersion;
     }
     // modify caching times
     if (!$useLongTTL) {
         WikiaLogger::instance()->info('rl.shortTTL', ['modules' => join(',', $modules), 'cb' => $cb, 'ts' => $ts]);
     }
     $cachingTimes = $wgResourceLoaderMaxage[$useLongTTL ? 'versioned' : 'unversioned'];
     $maxage = $cachingTimes['client'];
     $smaxage = $cachingTimes['server'];
     return true;
 }
Пример #8
0
 /**
  * Outputs a response to a resource load-request, including a content-type header.
  *
  * @param $context ResourceLoaderContext: Context in which a response should be formed
  */
 public function respond(ResourceLoaderContext $context)
 {
     global $wgResourceLoaderMaxage, $wgCacheEpoch;
     // Buffer output to catch warnings. Normally we'd use ob_clean() on the
     // top-level output buffer to clear warnings, but that breaks when ob_gzhandler
     // is used: ob_clean() will clear the GZIP header in that case and it won't come
     // back for subsequent output, resulting in invalid GZIP. So we have to wrap
     // the whole thing in our own output buffer to be sure the active buffer
     // doesn't use ob_gzhandler.
     // See http://bugs.php.net/bug.php?id=36514
     ob_start();
     wfProfileIn(__METHOD__);
     $errors = '';
     // Split requested modules into two groups, modules and missing
     $modules = array();
     $missing = array();
     foreach ($context->getModules() as $name) {
         if (isset($this->moduleInfos[$name])) {
             $module = $this->getModule($name);
             // Do not allow private modules to be loaded from the web.
             // This is a security issue, see bug 34907.
             if ($module->getGroup() === 'private') {
                 $errors .= $this->makeComment("Cannot show private module \"{$name}\"");
                 continue;
             }
             $modules[$name] = $this->getModule($name);
         } else {
             $missing[] = $name;
         }
     }
     // If a version wasn't specified we need a shorter expiry time for updates
     // to propagate to clients quickly
     if (is_null($context->getVersion())) {
         $maxage = $wgResourceLoaderMaxage['unversioned']['client'];
         $smaxage = $wgResourceLoaderMaxage['unversioned']['server'];
     } else {
         $maxage = $wgResourceLoaderMaxage['versioned']['client'];
         $smaxage = $wgResourceLoaderMaxage['versioned']['server'];
     }
     // Preload information needed to the mtime calculation below
     try {
         $this->preloadModuleInfo(array_keys($modules), $context);
     } catch (Exception $e) {
         // Add exception to the output as a comment
         $errors .= $this->makeComment($e->__toString());
     }
     wfProfileIn(__METHOD__ . '-getModifiedTime');
     // To send Last-Modified and support If-Modified-Since, we need to detect
     // the last modified time
     $mtime = wfTimestamp(TS_UNIX, $wgCacheEpoch);
     foreach ($modules as $module) {
         try {
             // Calculate maximum modified time
             $mtime = max($mtime, $module->getModifiedTime($context));
         } catch (Exception $e) {
             // Add exception to the output as a comment
             $errors .= $this->makeComment($e->__toString());
         }
     }
     wfProfileOut(__METHOD__ . '-getModifiedTime');
     if ($context->getOnly() === 'styles') {
         header('Content-Type: text/css; charset=utf-8');
     } else {
         header('Content-Type: text/javascript; charset=utf-8');
     }
     header('Last-Modified: ' . wfTimestamp(TS_RFC2822, $mtime));
     if ($context->getDebug()) {
         // Do not cache debug responses
         header('Cache-Control: private, no-cache, must-revalidate');
         header('Pragma: no-cache');
     } else {
         header("Cache-Control: public, max-age={$maxage}, s-maxage={$smaxage}");
         $exp = min($maxage, $smaxage);
         header('Expires: ' . wfTimestamp(TS_RFC2822, $exp + time()));
     }
     // If there's an If-Modified-Since header, respond with a 304 appropriately
     // Some clients send "timestamp;length=123". Strip the part after the first ';'
     // so we get a valid timestamp.
     $ims = $context->getRequest()->getHeader('If-Modified-Since');
     // Never send 304s in debug mode
     if ($ims !== false && !$context->getDebug()) {
         $imsTS = strtok($ims, ';');
         if ($mtime <= wfTimestamp(TS_UNIX, $imsTS)) {
             // There's another bug in ob_gzhandler (see also the comment at
             // the top of this function) that causes it to gzip even empty
             // responses, meaning it's impossible to produce a truly empty
             // response (because the gzip header is always there). This is
             // a problem because 304 responses have to be completely empty
             // per the HTTP spec, and Firefox behaves buggily when they're not.
             // See also http://bugs.php.net/bug.php?id=51579
             // To work around this, we tear down all output buffering before
             // sending the 304.
             // On some setups, ob_get_level() doesn't seem to go down to zero
             // no matter how often we call ob_get_clean(), so instead of doing
             // the more intuitive while ( ob_get_level() > 0 ) ob_get_clean();
             // we have to be safe here and avoid an infinite loop.
             for ($i = 0; $i < ob_get_level(); $i++) {
                 ob_end_clean();
             }
             header('HTTP/1.0 304 Not Modified');
             header('Status: 304 Not Modified');
             wfProfileOut(__METHOD__);
             return;
         }
     }
     // Generate a response
     $response = $this->makeModuleResponse($context, $modules, $missing);
     // Prepend comments indicating exceptions
     $response = $errors . $response;
     // Capture any PHP warnings from the output buffer and append them to the
     // response in a comment if we're in debug mode.
     if ($context->getDebug() && strlen($warnings = ob_get_contents())) {
         $response = $this->makeComment($warnings) . $response;
     }
     // Remove the output buffer and output the response
     ob_end_clean();
     echo $response;
     wfProfileOut(__METHOD__);
 }
Пример #9
0
 /**
  * Get the load.php URL that will produce this image.
  *
  * @param ResourceLoaderContext $context Any context
  * @param string $script URL to load.php
  * @param string|null $variant Variant to get the URL for
  * @param string $format Format to get the URL for, 'original' or 'rasterized'
  * @return string
  */
 public function getUrl(ResourceLoaderContext $context, $script, $variant, $format)
 {
     $query = ['modules' => $this->getModule(), 'image' => $this->getName(), 'variant' => $variant, 'format' => $format, 'lang' => $context->getLanguage(), 'version' => $context->getVersion()];
     return wfAppendQuery($script, $query);
 }
Пример #10
0
 /**
  * Get the URL or URLs to load for this module's CSS in debug mode.
  * The default behavior is to return a load.php?only=styles URL for
  * the module, but file-based modules will want to override this to
  * load the files directly. See also getScriptURLsForDebug()
  * 
  * @param $context ResourceLoaderContext: Context object
  * @return Array: array( mediaType => array( URL1, URL2, ... ), ... )
  */
 public function getStyleURLsForDebug(ResourceLoaderContext $context)
 {
     global $wgLoadScript;
     // TODO factor out to ResourceLoader static method and deduplicate from makeResourceLoaderLink()
     $query = array('modules' => $this->getName(), 'only' => 'styles', 'skin' => $context->getSkin(), 'user' => $context->getUser(), 'debug' => 'true', 'version' => $context->getVersion());
     ksort($query);
     return array('all' => array(wfAppendQuery($wgLoadScript, $query) . '&*'));
 }