社区文档构建进行中,欢迎编辑。社区答疑群(非官方):717421103

全站通知:

帮助:解析函数/css

来自WIKI实验室WIKI_BWIKI_哔哩哔哩
跳到导航 跳到搜索

css是一个解析函数。帮助:解析函数页列出了所有解析函数的说明。

css

为页面增加CSS。出自扩展 CSS


向页面添加CSS代码或CSS文件。CSS会被插入HTML的head中(而<bstyle>会将CSS插入在编写位置)。

语法

  • {{#css: CSS代码}}
  • {{#css: 页面名}}

注意

参数首字符不能为/,否则会被认定为服务器路径,导致CSS失效。

禁止出现部分CSS属性:

  • url
  • filter
  • var
  • attr
  • image, image-set
  • expression
  • accelerator
  • -o-link:, -o-link-source:, -o-replace

包含禁止特性的CSS会被替换为:/* insecure input */,导致整段CSS无效。 此检测由Mediawiki的Sanitizer::checkCss方法进行。

要用这些属性,可以使用不带检测的<bstyle>

示例

{{#css: 
.a_css_demo{
  color:red;
} 
}}<span class="a_css_demo">文字</span>

效果:

文字

更多用法

模板中防止多次插入CSS。

  • 代码冗余会影响搜索引擎收录。如果是在被大量使用的模板中重复载入CSS,可能会导致页面异常。
{{#if:{{#varexists:防止多次加载CSS_XXX}} | |{{#vardefine:防止多次加载CSS_XXX|1}} {{#css:
/* css代码 */
}}}}

此模式通过判断变量是否定义,来判断变量名对应的CSS是否加载。

类似的,bstyle标签也可以使用这种写法:

{{#if:{{#varexists:页面内同一变量名中的CSS只会载入一次}} || {{#vardefine:页面内同一变量名中的CSS只会载入一次 | 1 }}<bstyle>/*<pre>*/
/* css代码 */
/*</pre>*/</bstyle>}}

底层代码

/** https://github.com/wikimedia/mediawiki-extensions-CSS/blob/REL1_37/CSS.class.php
 * @param Parser &$parser
 * @param string $css
 * @return string
 */
public function cssRender( Parser $parser, string $css ): string {
	$css = trim( $css );
	if ( $css === '' ) {
		return '';
	}
	$title = $this->titleFactory->newFromText( $css );
	$identifier = $this->config->get( 'CSSIdentifier' );
	$rawProtection = [ $identifier => '1' ];
	$headItem = '<!-- Begin Extension:CSS -->';

	if ( $title && $title->exists() ) {
		# Article actually in the db
		$params = [
			'action' => 'raw',
			'ctype' => 'text/css',
		] + $rawProtection;
		$url = $title->getLocalURL( $params );
		$headItem .= Html::linkedStyle( $url );
	} elseif ( $css[0] === '/' ) {
		# Regular file
		$base = $this->config->get( 'CSSPath' ) === false ?
			$this->config->get( MainConfigNames::StylePath ) :
			$this->config->get( 'CSSPath' );
		// The replacement for \ to / is to workaround a path traversal,
		// per T369486.
		// TODO: Implement a proper URL parser. There may be more niche URL
		// shenanigans one could get up to that MediaWiki's parser does not
		// handle, but which the browser does. The most surefire way to
		// guarantee that no tomfoolery happens is to 100% replicate what
		// the browser does and not only like 90% of it.
		$path = str_replace( '\\', '/', $css );
		$url = wfAppendQuery( $base . $path, $rawProtection );

		# Verify the expanded URL is still using the base URL
		$expandedUrl = $this->urlUtils->expand( $url );
		$expandedBase = $this->urlUtils->expand( $base );
		if ( $expandedUrl && $expandedBase && strpos( $expandedUrl, $expandedBase ) === 0 ) {
			$headItem .= Html::linkedStyle( $url );
		} else {
			$headItem .= '<!-- Invalid/malicious path  -->';
		}
	} else {
		# sanitized user CSS
		$css = $this->sanitizeCSS( $css );

		# Encode data URI and append link tag
		$dataPrefix = 'data:text/css;charset=UTF-8;base64,';
		$url = $dataPrefix . base64_encode( $css );

		$headItem .= Html::linkedStyle( $url );
	}

	$headItem .= '<!-- End Extension:CSS -->';
	$parser->getOutput()->addHeadItem( $headItem );
	return '';
}




/** mediawiki-1.37.0\includes\parser\Sanitizer.php
* Pick apart some CSS and check it for forbidden or unsafe structures.
* Returns a sanitized string. This sanitized string will have
* character references and escape sequences decoded and comments
* stripped (unless it is itself one valid comment, in which case the value
* will be passed through). If the input is just too evil, only a comment
* complaining about evilness will be returned.
*
* Currently URL references, 'expression', 'tps' are forbidden.
*
* NOTE: Despite the fact that character references are decoded, the
* returned string may contain character references given certain
* clever input strings. These character references must
* be escaped before the return value is embedded in HTML.
*
* @param string $value
* @return string
*/
public static function checkCss( $value ) {
	$value = self::normalizeCss( $value );

	// Reject problematic keywords and control characters
	if ( preg_match( '/[\000-\010\013\016-\037\177]/', $value ) ||
		strpos( $value, UtfNormal\Constants::UTF8_REPLACEMENT ) !== false ) {
		return '/* invalid control char */';
	} elseif ( preg_match(
		'! expression
			| filter\s*:
			| accelerator\s*:
			| -o-link\s*:
			| -o-link-source\s*:
			| -o-replace\s*:
			| url\s*\(
			| image\s*\(
			| image-set\s*\(
			| attr\s*\([^)]+[\s,]+url
			| var\s*\(
		!ix', $value ) ) {
		return '/* insecure input */';
	}
	return $value;
}

/** mediawiki-1.37.0\includes\parser\Sanitizer.php
* Normalize CSS into a format we can easily search for hostile input
*  - decode character references
*  - decode escape sequences
*  - remove comments, unless the entire value is one single comment
* @param string $value the css string
* @return string normalized css
*/
public static function normalizeCss( $value ) {
	// Decode character references like &#123;
	$value = self::decodeCharReferences( $value );

	// Decode escape sequences and line continuation
	// See the grammar in the CSS 2 spec, appendix D.
	// This has to be done AFTER decoding character references.
	// This means it isn't possible for this function to return
	// unsanitized escape sequences. It is possible to manufacture
	// input that contains character references that decode to
	// escape sequences that decode to character references, but
	// it's OK for the return value to contain character references
	// because the caller is supposed to escape those anyway.
	static $decodeRegex;
	if ( !$decodeRegex ) {
		$space = '[\\x20\\t\\r\\n\\f]';
		$nl = '(?:\\n|\\r\\n|\\r|\\f)';
		$backslash = '\\\\';
		$decodeRegex = "/ $backslash
			(?:
				($nl) |  # 1. Line continuation
				([0-9A-Fa-f]{1,6})$space? |  # 2. character number
				(.) | # 3. backslash cancelling special meaning
				() | # 4. backslash at end of string
			)/xu";
	}
	$value = preg_replace_callback( $decodeRegex,
		[ __CLASS__, 'cssDecodeCallback' ], $value );

	// Let the value through if it's nothing but a single comment, to
	// allow other functions which may reject it to pass some error
	// message through.
	if ( !preg_match( '! ^ \s* /\* [^*\\/]* \*/ \s* $ !x', $value ) ) {
		// Remove any comments; IE gets token splitting wrong
		// This must be done AFTER decoding character references and
		// escape sequences, because those steps can introduce comments
		// This step cannot introduce character references or escape
		// sequences, because it replaces comments with spaces rather
		// than removing them completely.
		$value = StringUtils::delimiterReplace( '/*', '*/', ' ', $value );

		// Remove anything after a comment-start token, to guard against
		// incorrect client implementations.
		$commentPos = strpos( $value, '/*' );
		if ( $commentPos !== false ) {
			$value = substr( $value, 0, $commentPos );
		}
	}

	return $value;
}
代码逻辑:
  • 首先判断输入的css是否是存在的页面标题或服务器存在的样式文件。如是则直接添加对应的link标签加载css
    • 首先尝试将输入的css作为标题,检测是否存在
    • 然后判断首个字符是不是 /,如果是作为服务器路径处理
  • 否则使用 sanitizeCSS 方法清理css,对css进行base64编码,再加入link标签
  • 其中,sanitizeCSS 是Mediawiki的内置方法,它会规范化CSS、并进行安全检测。如未通过,css将被替换为报错信息。
  • 规范化包括:解码字符引用、解码和处理转义序列,最后移除注释
  • 不安全的控制字符检测基于正则:/[\000-\010\013\016-\037\177]/
  • 不安全的CSS关键词包括:
    • expression: 旧版本的Internet Explorer中,expression属性允许在CSS中执行JavaScript代码。
    • accelerator
    • filter
    • -o-link, -o-link-source, -o-replace
    • url
    • image, image-set
    • attr
    • var
  • 不安全的css会被替换为/* insecure input */

实际用例

一些Wiki使用了相关特性,如下所示这个静态列表可能在下列页面更改后过时仅供批判性参考
碧蓝航线 - blhx

原神 - ys

战双帕弥什 - zspms

明日方舟 - arknights

恋与深空 - lysk

崩坏:星穹铁道 - sr

代号鸢 - yuan

赛马娘 - umamusume

第五人格 - dwrg

坎特伯雷公主与骑士唤醒冠军之剑的奇幻冒险 - gt

三国杀 - sgs

尘白禁区 - sonw

黑神话:悟空 - wukong

WIKI实验室 - tools

地下城堡2 - dxcb2

战争雷霆 - warthunder

东方归言录 - touhoulostword

卡拉彼丘 - klbq

白荆回廊 - bjhl

女神转生 - persona

赛尔计划 - seerplan

幻塔 - ht

雷索纳斯 - resonance

绝区零 - zzz

重返未来:1999 - reverse1999

偶像大师灰姑娘女孩 - imascg

公主连结 - pcr

ミナシゴノシゴト - mnsg

无期迷途 - wqmt

奇迹暖暖 - qjnn

赛尔号 - seer

地下城堡3 - dxcb3

红警3 - redalert3

孙美琪疑案 - sunmeiqi

鸣潮 - wutheringwaves

交错战线 - crosscore

千年之旅 - elf

生死狙击2 - ssjj2

世界之外 - world

戴森球计划 - dsp

梦幻模拟战 - langrisser

StardewValley星露谷物语 - stardewvalley

赛尔号星球大战 - seerwar

觅长生 - mcs

QQ飞车手游 - qqspeed

放置江湖 - fzjh

方舟指令 - fzzl

少前2:追放 - gf2

偶像荣耀/idoly pride - idolypride

深空之眼 - dhmmr