Файловый менеджер - Редактировать - /var/www/html/ResourceLoader.zip
Ðазад
PK ! ᚫc c FilePath.phpnu �Iw�� <?php /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * * @file */ namespace MediaWiki\ResourceLoader; use RuntimeException; /** * A path to a bundled file (such as JavaScript or CSS), along with a remote and local base path. * * This is for use with FileModule. Base path may be `null`, which indicates that the * path is expanded relative to the corresponding base path of the FileModule object instead. * * @ingroup ResourceLoader * @since 1.17 */ class FilePath { /** @var string|null Local base path */ protected ?string $localBasePath; /** @var string|null Remote base path */ protected ?string $remoteBasePath; /** @var string Path to the file */ protected string $path; /** * @param string $path Relative path to the file, no leading slash. * @param string|null $localBasePath Base path to prepend when generating a local path. * @param string|null $remoteBasePath Base path to prepend when generating a remote path. * Should not have a trailing slash unless at web document root. */ public function __construct( string $path, ?string $localBasePath = null, ?string $remoteBasePath = null ) { $this->path = $path; $this->localBasePath = $localBasePath; $this->remoteBasePath = $remoteBasePath; } /** * @return string * @throws RuntimeException If the base path was not provided. You must either provide the base * path in the constructor, or use getPath() instead and add the base path from a FileModule. */ public function getLocalPath(): string { if ( $this->localBasePath === null ) { throw new RuntimeException( 'Base path was not provided' ); } return "{$this->localBasePath}/{$this->path}"; } /** * @return string * @throws RuntimeException If the base path was not provided. You must either provide the base * path in the constructor, or use getPath() instead and add the base path from a FileModule. */ public function getRemotePath(): string { if ( $this->remoteBasePath === null ) { throw new RuntimeException( 'Base path was not provided' ); } if ( $this->remoteBasePath === '/' ) { // In document root // Don't insert another slash (T284391). return $this->remoteBasePath . $this->path; } return "{$this->remoteBasePath}/{$this->path}"; } /** @return string|null */ public function getLocalBasePath(): ?string { return $this->localBasePath; } /** @return string|null */ public function getRemoteBasePath(): ?string { return $this->remoteBasePath; } /** @return string */ public function getPath(): string { return $this->path; } /** * Set the base path if it has not already been set. * * @param string $localBasePath * @param string $remoteBasePath */ public function initBasePaths( string $localBasePath, string $remoteBasePath ) { if ( $this->localBasePath === null ) { $this->localBasePath = $localBasePath; } if ( $this->remoteBasePath === null ) { $this->remoteBasePath = $remoteBasePath; } } } PK ! n�ʋ � OOUIModule.phpnu �Iw�� <?php /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * * @file */ namespace MediaWiki\ResourceLoader; use InvalidArgumentException; use MediaWiki\Registration\ExtensionRegistry; /** * Convenience methods for dealing with OOUI themes and their relations to MW skins. * * @ingroup ResourceLoader * @internal */ trait OOUIModule { /** @var string[] */ protected static $knownScriptsModules = [ 'core' ]; /** @var string[] */ protected static $knownStylesModules = [ 'core', 'widgets', 'toolbars', 'windows' ]; /** @var string[] */ protected static $knownImagesModules = [ 'indicators', // Extra icons 'icons-accessibility', 'icons-alerts', 'icons-content', 'icons-editing-advanced', 'icons-editing-citation', 'icons-editing-functions', 'icons-editing-core', 'icons-editing-list', 'icons-editing-styling', 'icons-interactions', 'icons-layout', 'icons-location', 'icons-media', 'icons-moderation', 'icons-movement', 'icons-user', 'icons-wikimedia', ]; /** @var string[] Note that keys must be lowercase, values TitleCase. */ protected static $builtinSkinThemeMap = [ 'default' => 'WikimediaUI', ]; /** @var string[][] Note that keys must be TitleCase. */ protected static $builtinThemePaths = [ 'WikimediaUI' => [ 'scripts' => 'resources/lib/ooui/oojs-ui-wikimediaui.js', 'styles' => 'resources/lib/ooui/oojs-ui-{module}-wikimediaui.css', 'images' => 'resources/lib/ooui/themes/wikimediaui/{module}.json', ], 'Apex' => [ 'scripts' => 'resources/lib/ooui/oojs-ui-apex.js', 'styles' => 'resources/lib/ooui/oojs-ui-{module}-apex.css', 'images' => 'resources/lib/ooui/themes/apex/{module}.json', ], ]; /** * Return a map of skin names (in lowercase) to OOUI theme names, defining which theme a given * skin should use. * * @return array */ public static function getSkinThemeMap() { $themeMap = self::$builtinSkinThemeMap; $themeMap += ExtensionRegistry::getInstance()->getAttribute( 'SkinOOUIThemes' ); return $themeMap; } /** * Return a map of theme names to lists of paths from which a given theme should be loaded. * * Keys are theme names, values are associative arrays. Keys of the inner array are 'scripts', * 'styles', or 'images', and values are paths. Paths may be strings or FilePaths. * * Additionally, the string '{module}' in paths represents the name of the module to load. * * @return array */ protected static function getThemePaths() { $themePaths = self::$builtinThemePaths; $themePaths += ExtensionRegistry::getInstance()->getAttribute( 'OOUIThemePaths' ); [ $defaultLocalBasePath, $defaultRemoteBasePath ] = FileModule::extractBasePaths(); // Allow custom themes' paths to be relative to the skin/extension that defines them, // like with ResourceModuleSkinStyles foreach ( $themePaths as &$paths ) { [ $localBasePath, $remoteBasePath ] = FileModule::extractBasePaths( $paths ); if ( $localBasePath !== $defaultLocalBasePath || $remoteBasePath !== $defaultRemoteBasePath ) { foreach ( $paths as &$path ) { $path = new FilePath( $path, $localBasePath, $remoteBasePath ); } } } return $themePaths; } /** * Return a path to load given module of given theme from. * * The file at this path may not exist. This should be handled by the caller (throwing an error or * falling back to default theme). * * @param string $theme OOUI theme name, for example 'WikimediaUI' or 'Apex' * @param string $kind Kind of the module: 'scripts', 'styles', or 'images' * @param string $module Module name, for valid values see $knownScriptsModules, * $knownStylesModules, $knownImagesModules * @return string|FilePath */ protected function getThemePath( $theme, $kind, $module ) { $paths = self::getThemePaths(); $path = $paths[$theme][$kind]; if ( $path instanceof FilePath ) { $path = new FilePath( str_replace( '{module}', $module, $path->getPath() ), $path->getLocalBasePath(), $path->getRemoteBasePath() ); } else { $path = str_replace( '{module}', $module, $path ); } return $path; } /** * @param string $theme See getThemePath() * @param string $module See getThemePath() * @return string|FilePath */ protected function getThemeScriptsPath( $theme, $module ) { if ( !in_array( $module, self::$knownScriptsModules ) ) { throw new InvalidArgumentException( "Invalid OOUI scripts module '$module'" ); } return $this->getThemePath( $theme, 'scripts', $module ); } /** * @param string $theme See getThemePath() * @param string $module See getThemePath() * @return string|FilePath */ protected function getThemeStylesPath( $theme, $module ) { if ( !in_array( $module, self::$knownStylesModules ) ) { throw new InvalidArgumentException( "Invalid OOUI styles module '$module'" ); } return $this->getThemePath( $theme, 'styles', $module ); } /** * @param string $theme See getThemePath() * @param string $module See getThemePath() * @return string|FilePath */ protected function getThemeImagesPath( $theme, $module ) { if ( !in_array( $module, self::$knownImagesModules ) ) { throw new InvalidArgumentException( "Invalid OOUI images module '$module'" ); } return $this->getThemePath( $theme, 'images', $module ); } } PK ! ��D�� � MessageBlobStore.phpnu �Iw�� <?php /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * * @file * @author Roan Kattouw * @author Trevor Parscal */ namespace MediaWiki\ResourceLoader; use MediaWiki\Json\FormatJson; use MediaWiki\MediaWikiServices; use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; use Wikimedia\ObjectCache\WANObjectCache; use Wikimedia\Rdbms\Database; /** * This class generates message blobs for use by ResourceLoader. * * A message blob is a JSON object containing the interface messages for a * certain module in a certain language. * * @ingroup ResourceLoader * @since 1.17 */ class MessageBlobStore implements LoggerAwareInterface { /** @var ResourceLoader */ private $resourceloader; /** @var LoggerInterface */ protected $logger; /** @var WANObjectCache */ protected $wanCache; /** * @param ResourceLoader $rl * @param LoggerInterface|null $logger * @param WANObjectCache|null $wanObjectCache */ public function __construct( ResourceLoader $rl, ?LoggerInterface $logger, ?WANObjectCache $wanObjectCache ) { $this->resourceloader = $rl; $this->logger = $logger ?: new NullLogger(); // NOTE: when changing this assignment, make sure the code in the instantiator for // LocalisationCache which calls MessageBlobStore::clearGlobalCacheEntry() uses the // same cache object. $this->wanCache = $wanObjectCache ?: MediaWikiServices::getInstance() ->getMainWANObjectCache(); } /** * @since 1.27 * @param LoggerInterface $logger */ public function setLogger( LoggerInterface $logger ) { $this->logger = $logger; } /** * Get the message blob for a module * * @since 1.27 * @param Module $module * @param string $lang Language code * @return string JSON */ public function getBlob( Module $module, $lang ) { $blobs = $this->getBlobs( [ $module->getName() => $module ], $lang ); return $blobs[$module->getName()]; } /** * Get the message blobs for a set of modules * * @since 1.27 * @param Module[] $modules Array of module objects keyed by name * @param string $lang Language code * @return string[] An array mapping module names to message blobs */ public function getBlobs( array $modules, $lang ) { // Each cache key for a message blob by module name and language code also has a generic // check key without language code. This is used to invalidate any and all language subkeys // that exist for a module from the updateMessage() method. $checkKeys = [ self::makeGlobalPurgeKey( $this->wanCache ) ]; $cacheKeys = []; foreach ( $modules as $name => $module ) { $cacheKey = $this->makeBlobCacheKey( $name, $lang, $module ); $cacheKeys[$name] = $cacheKey; $checkKeys[$cacheKey][] = $this->makeModulePurgeKey( $name ); } $curTTLs = []; $result = $this->wanCache->getMulti( array_values( $cacheKeys ), $curTTLs, $checkKeys ); $blobs = []; foreach ( $modules as $name => $module ) { $key = $cacheKeys[$name]; if ( !isset( $result[$key] ) || $curTTLs[$key] === null || $curTTLs[$key] < 0 ) { $blobs[$name] = $this->recacheMessageBlob( $key, $module, $lang ); } else { // Use unexpired cache $blobs[$name] = $result[$key]; } } return $blobs; } /** * Global check key for ::clear() * * @param WANObjectCache $cache * @return string Cache key */ private static function makeGlobalPurgeKey( WANObjectCache $cache ) { return $cache->makeGlobalKey( 'resourceloader-messageblob' ); } /** * Per-module check key, for ::updateMessage() * * @param string $name * @return string Cache key */ private function makeModulePurgeKey( $name ) { return $this->wanCache->makeKey( 'resourceloader-messageblob', $name ); } /** * @param string $name * @param string $lang * @param Module $module * @return string Cache key */ private function makeBlobCacheKey( $name, $lang, Module $module ) { $messages = array_values( array_unique( $module->getMessages() ) ); sort( $messages ); return $this->wanCache->makeKey( 'resourceloader-messageblob', $name, $lang, md5( json_encode( $messages ) ) ); } /** * @since 1.27 * @param string $cacheKey * @param Module $module * @param string $lang * @return string JSON blob */ protected function recacheMessageBlob( $cacheKey, Module $module, $lang ) { $blob = $this->generateMessageBlob( $module, $lang ); $cache = $this->wanCache; $dbr = MediaWikiServices::getInstance()->getConnectionProvider()->getReplicaDatabase(); $cache->set( $cacheKey, $blob, // Add part of a day to TTL to avoid all modules expiring at once $cache::TTL_WEEK + mt_rand( 0, $cache::TTL_DAY ), Database::getCacheSetOptions( $dbr ) ); return $blob; } /** * Invalidate cache keys for modules using this message key. * Called by MessageCache when a message has changed. * * @param string $key Message key */ public function updateMessage( $key ): void { $moduleNames = $this->resourceloader->getModulesByMessage( $key ); foreach ( $moduleNames as $moduleName ) { // Use the default holdoff TTL to account for database replica DB lag // which can affect MessageCache. $this->wanCache->touchCheckKey( $this->makeModulePurgeKey( $moduleName ) ); } } /** * Invalidate cache keys for all known modules. * * Used by purgeMessageBlobStore.php */ public function clear() { self::clearGlobalCacheEntry( $this->wanCache ); } /** * Invalidate cache keys for all known modules. * * Used by LocalisationCache and DatabaseUpdater after regenerating l10n cache. * * @param WANObjectCache $cache */ public static function clearGlobalCacheEntry( WANObjectCache $cache ) { // Disable holdoff TTL because: // - LocalisationCache is populated by messages on-disk and don't have DB lag, // thus there is no need for hold off. We only clear it after new localisation // updates are known to be deployed to all servers. // - This global check key invalidates message blobs for all modules for all wikis // in cache contexts (e.g. languages, skins). Setting a hold-off on this key could // cause a cache stampede since no values would be stored for several seconds. $cache->touchCheckKey( self::makeGlobalPurgeKey( $cache ), $cache::HOLDOFF_TTL_NONE ); } /** * @since 1.27 * @param string $key Message key * @param string $lang Language code * @return string|null */ protected function fetchMessage( $key, $lang ) { $message = wfMessage( $key )->inLanguage( $lang ); if ( !$message->exists() ) { $this->logger->warning( 'Failed to find {messageKey} ({lang})', [ 'messageKey' => $key, 'lang' => $lang, ] ); $value = null; } else { $value = $message->plain(); } return $value; } /** * Generate the message blob for a given module in a given language. * * @param Module $module * @param string $lang Language code * @return string JSON blob */ private function generateMessageBlob( Module $module, $lang ) { $messages = []; foreach ( $module->getMessages() as $key ) { $value = $this->fetchMessage( $key, $lang ); // If the message does not exist, omit it from the blob so that // client-side mw.message may do its own existence handling. if ( $value !== null ) { $messages[$key] = $value; } } $json = FormatJson::encode( (object)$messages, false, FormatJson::UTF8_OK ); // @codeCoverageIgnoreStart if ( $json === false ) { $this->logger->warning( 'Failed to encode message blob for {module} ({lang})', [ 'module' => $module->getName(), 'lang' => $lang, ] ); $json = '{}'; } // codeCoverageIgnoreEnd return $json; } } PK ! ���QB B OOUIIconPackModule.phpnu �Iw�� <?php /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * * @file */ namespace MediaWiki\ResourceLoader; use InvalidArgumentException; /** * Allows loading arbitrary sets of OOUI icons. * * @ingroup ResourceLoader * @since 1.34 */ class OOUIIconPackModule extends OOUIImageModule { public function __construct( array $options = [], $localBasePath = null ) { parent::__construct( $options, $localBasePath ); if ( !isset( $this->definition['icons'] ) || !$this->definition['icons'] ) { throw new InvalidArgumentException( "Parameter 'icons' must be given." ); } // A few things check for the "icons" prefix on this value, so specify it even though // we don't use it for actually loading the data, like in the other modules. $this->definition['themeImages'] = 'icons'; } private function getIcons(): array { // @phan-suppress-next-line PhanTypeArraySuspiciousNullable Checked in the constructor return $this->definition['icons']; } protected function loadOOUIDefinition( $theme, $unused ): array { // This is shared between instances of this class, so we only have to load the JSON files once static $data = []; if ( !isset( $data[$theme] ) ) { $data[$theme] = []; // Load and merge the JSON data for all "icons-foo" modules foreach ( self::$knownImagesModules as $module ) { if ( str_starts_with( $module, 'icons' ) ) { $moreData = $this->readJSONFile( $this->getThemeImagesPath( $theme, $module ) ); if ( $moreData ) { $data[$theme] = array_replace_recursive( $data[$theme], $moreData ); } } } } $definition = $data[$theme]; // Filter out the data for all other icons, leaving only the ones we want for this module $iconsNames = $this->getIcons(); foreach ( $definition['images'] as $iconName => $_ ) { if ( !in_array( $iconName, $iconsNames ) ) { unset( $definition['images'][$iconName] ); } } return $definition; } public static function extractLocalBasePath( array $options, $localBasePath = null ) { global $IP; // Ignore any 'localBasePath' present in $options, this always refers to files in MediaWiki core return $localBasePath ?? $IP; } } PK ! �WGl� � OOUIFileModule.phpnu �Iw�� <?php /** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * * @file */ namespace MediaWiki\ResourceLoader; /** * Module which magically loads the right skinScripts and skinStyles for every * skin, using the specified OOUI theme for each. * * @ingroup ResourceLoader * @internal */ class OOUIFileModule extends FileModule { use OOUIModule; /** @var array<string,string|FilePath> */ private $themeStyles = []; public function __construct( array $options = [] ) { if ( isset( $options['themeScripts'] ) ) { $skinScripts = $this->getSkinSpecific( $options['themeScripts'], 'scripts' ); $options['skinScripts'] = $this->extendSkinSpecific( $options['skinScripts'] ?? [], $skinScripts ); } if ( isset( $options['themeStyles'] ) ) { $this->themeStyles = $this->getSkinSpecific( $options['themeStyles'], 'styles' ); } parent::__construct( $options ); } public function setSkinStylesOverride( array $moduleSkinStyles ): void { parent::setSkinStylesOverride( $moduleSkinStyles ); $this->skinStyles = $this->extendSkinSpecific( $this->skinStyles, $this->themeStyles ); } /** * Helper function to generate values for 'skinStyles' and 'skinScripts'. * * @param string $module Module to generate skinStyles/skinScripts for: * 'core', 'widgets', 'toolbars', 'windows' * @param string $which 'scripts' or 'styles' * @return array<string,string|FilePath> */ private function getSkinSpecific( $module, $which ): array { $themes = self::getSkinThemeMap(); return array_combine( array_keys( $themes ), array_map( function ( $theme ) use ( $module, $which ) { if ( $which === 'scripts' ) { return $this->getThemeScriptsPath( $theme, $module ); } else { return $this->getThemeStylesPath( $theme, $module ); } }, array_values( $themes ) ) ); } /** * Prepend theme-specific resources on behalf of the skin. * * The expected order of styles and scripts in the output is: * * 1. Theme-specific resources for a given skin. * * 2. Module-defined resources for a specific skin, * falling back to module-defined "default" skin resources. * * 3. Skin-defined resources for a specific module, which can either * append to or replace the "default" (via ResourceModuleSkinStyles in skin.json) * Note that skins can only define resources for a module if that * module does not already explicitly provide resources for that skin. * * @param array $skinSpecific Module-defined 'skinScripts' or 'skinStyles'. * @param array $themeSpecific * @return array Modified $skinSpecific */ private function extendSkinSpecific( array $skinSpecific, array $themeSpecific ): array { // If the module or skin already set skinStyles/skinScripts, prepend ours foreach ( $skinSpecific as $skin => $files ) { if ( !is_array( $files ) ) { $files = [ $files ]; } if ( isset( $themeSpecific[$skin] ) ) { $skinSpecific[$skin] = array_merge( [ $themeSpecific[$skin] ], $files ); } elseif ( isset( $themeSpecific['default'] ) ) { $skinSpecific[$skin] = array_merge( [ $themeSpecific['default'] ], $files ); } } // If the module has no skinStyles/skinScripts for a skin, then set ours foreach ( $themeSpecific as $skin => $file ) { if ( !isset( $skinSpecific[$skin] ) ) { $skinSpecific[$skin] = [ $file ]; } } return $skinSpecific; } } PK ! ��^<