Skip to content

Commit 552c2d5

Browse files
committed
Add create_css_string
See WordPress/gutenberg#76782
1 parent cb470bf commit 552c2d5

1 file changed

Lines changed: 36 additions & 60 deletions

File tree

src/wp-includes/css-api/class-wp-css-token-processor.php

Lines changed: 36 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -831,14 +831,14 @@ public function set_token_value( string $new_value ): bool {
831831
$this->lexical_updates[] = array(
832832
'start' => $this->token_value_starts_at,
833833
'length' => $this->token_value_length,
834-
'text' => $this->escape_url_value( $new_value ),
834+
'text' => $this->create_css_string( $new_value ),
835835
);
836836
return true;
837837
case self::TOKEN_STRING:
838838
$this->lexical_updates[] = array(
839839
'start' => $this->token_starts_at,
840840
'length' => $this->token_length,
841-
'text' => $this->escape_url_value( $new_value ),
841+
'text' => $this->create_css_string( $new_value ),
842842
);
843843
return true;
844844
default:
@@ -848,66 +848,42 @@ public function set_token_value( string $new_value ): bool {
848848
}
849849

850850
/**
851-
* Escapes a URL value for use in quoted url() syntax.
851+
* Create a quoted CSS string from a plain PHP string value.
852852
*
853-
* Always returns a quoted URL string since they're easier
854-
* to escape. Quoted URLs are consumed using the string token
855-
* rules, and the only values we need to escape in strings, are:
856-
*
857-
* * Trailing quote.
858-
* * Newlines. That amounts to \n, \r, \f, \r\n when preprocessing is considered.
859-
* * U+005C REVERSE SOLIDUS (\)
860-
*
861-
* @see https://www.w3.org/TR/css-syntax-3/#consume-url-token
853+
* @see https://www.w3.org/TR/css-syntax-3/#escaping
862854
*/
863-
private function escape_url_value( string $unescaped ): string {
864-
$escaped = '';
865-
$at = 0;
866-
while ( $at < strlen( $unescaped ) ) {
867-
$safe_len = strcspn( $unescaped, "\n\r\f\\\"", $at );
868-
if ( $safe_len > 0 ) {
869-
$escaped .= substr( $unescaped, $at, $safe_len );
870-
$at += $safe_len;
871-
continue;
872-
}
873-
874-
$unsafe_char = $unescaped[ $at ];
875-
switch ( $unsafe_char ) {
876-
case "\r":
877-
++$at;
878-
/**
879-
* Add a trailing space to prevent accidentally creating a
880-
* wrong escape sequence. This is a valid CSS syntax and
881-
* CSS parsers will ignore that whitespace.
882-
*
883-
* Without the space, "carriage\return" would be encoded as "carriage\aeturn",
884-
* making `e` a part of the escape sequence `\ae` which is not
885-
* what the caller intended.
886-
*/
887-
$escaped .= '\\a ';
888-
if ( strlen( $unescaped ) > $at + 1 && "\n" === $unescaped[ $at + 1 ] ) {
889-
++$at;
890-
}
891-
break;
892-
case "\f":
893-
case "\n":
894-
++$at;
895-
$escaped .= '\\a ';
896-
break;
897-
case '\\':
898-
++$at;
899-
$escaped .= '\\5C ';
900-
break;
901-
case '"':
902-
++$at;
903-
$escaped .= '\\22 ';
904-
break;
905-
default:
906-
_doing_it_wrong( __METHOD__, 'Unexpected character in URL value: ' . $unsafe_char, '1.0.0' );
907-
break;
908-
}
909-
}
910-
return '"' . $escaped . '"';
855+
private function create_css_string( string $value ): string {
856+
$escaped = strtr(
857+
$value,
858+
array(
859+
'\\' => '\\5C ',
860+
861+
// Pre-processing replaces NULLs and some newlines. Replace and escape as necessary.
862+
"\0" => "\u{FFFD}",
863+
864+
// Normalize and replace newlines. https://www.w3.org/TR/css-syntax-3/#input-preprocessing
865+
"\r\n" => '\\A ',
866+
"\r" => '\\A ',
867+
"\f" => '\\A ',
868+
869+
// Newlines must be escaped in CSS strings.
870+
"\n" => '\\A ',
871+
872+
// HTML syntax may be problematic.
873+
'<' => '\\3C ',
874+
'>' => '\\3E ',
875+
'&' => '\\26 ',
876+
877+
// CSS syntax may be problematic.
878+
',' => '\\2C ',
879+
';' => '\\3B ',
880+
'{' => '\\7B ',
881+
'}' => '\\7D ',
882+
'"' => '\\22 ',
883+
"'" => '\\27 ',
884+
)
885+
);
886+
return "\"{$escaped}\"";
911887
}
912888

913889
/**

0 commit comments

Comments
 (0)