2015-08-17 17:00:26 -07:00
< ? php
/**
* @ file
* Contains \Drupal\Component\Utility\SafeMarkup .
*/
namespace Drupal\Component\Utility ;
/**
* Manages known safe strings for rendering at the theme layer .
*
* The Twig theme engine autoescapes string variables in the template , so it
* is possible for a string of markup to become double - escaped . SafeMarkup
* provides a store for known safe strings and methods to manage them
* throughout the page request .
*
2015-09-04 13:20:09 -07:00
* Strings sanitized by self :: checkPlain () and self :: escape () are automatically
* marked safe , as are markup strings created from @ link theme_render render
* arrays @ endlink via drupal_render () .
2015-08-17 17:00:26 -07:00
*
* This class should be limited to internal use only . Module developers should
* instead use the appropriate
* @ link sanitization sanitization functions @ endlink or the
* @ link theme_render theme and render systems @ endlink so that the output can
* can be themed , escaped , and altered properly .
*
* @ see TwigExtension :: escapeFilter ()
* @ see twig_render_template ()
* @ see sanitization
* @ see theme_render
*/
class SafeMarkup {
/**
* The list of safe strings .
*
2015-09-04 13:20:09 -07:00
* Strings in this list are marked as secure for the entire page render , not
* just the code or element that set it . Therefore , only valid HTML should be
* marked as safe ( never partial markup ) . For example , you should never mark
* string such as '<' or '<script>' safe .
*
2015-08-17 17:00:26 -07:00
* @ var array
*/
protected static $safeStrings = array ();
/**
2015-09-04 13:20:09 -07:00
* Checks if a string is safe to output .
2015-08-17 17:00:26 -07:00
*
2015-09-04 13:20:09 -07:00
* @ param string | \Drupal\Component\Utility\SafeStringInterface $string
* The content to be checked .
2015-08-17 17:00:26 -07:00
* @ param string $strategy
2015-09-04 13:20:09 -07:00
* The escaping strategy . Defaults to 'html' . Two escaping strategies are
* supported by default :
2015-08-17 17:00:26 -07:00
* - 'html' : ( default ) The string is safe for use in HTML code .
* - 'all' : The string is safe for all use cases .
* See the
* @ link http :// twig . sensiolabs . org / doc / filters / escape . html Twig escape documentation @ endlink
* for more information on escaping strategies in Twig .
*
* @ return bool
* TRUE if the string has been marked secure , FALSE otherwise .
*/
public static function isSafe ( $string , $strategy = 'html' ) {
// Do the instanceof checks first to save unnecessarily casting the object
// to a string.
return $string instanceOf SafeStringInterface || isset ( static :: $safeStrings [( string ) $string ][ $strategy ]) ||
isset ( static :: $safeStrings [( string ) $string ][ 'all' ]);
}
/**
* Adds previously retrieved known safe strings to the safe string list .
*
2015-09-04 13:20:09 -07:00
* This method is for internal use . Do not use it to prevent escaping of
* markup ; instead , use the appropriate
* @ link sanitization sanitization functions @ endlink or the
* @ link theme_render theme and render systems @ endlink so that the output
* can be themed , escaped , and altered properly .
2015-08-17 17:00:26 -07:00
*
2015-09-04 13:20:09 -07:00
* This marks strings as secure for the entire page render , not just the code
* or element that set it . Therefore , only valid HTML should be
* marked as safe ( never partial markup ) . For example , you should never do :
* @ code
* SafeMarkup :: setMultiple ([ '<' => [ 'html' => TRUE ]]);
* @ endcode
* or :
* @ code
* SafeMarkup :: setMultiple ([ '<script>' => [ 'all' => TRUE ]]);
* @ endcode
2015-08-17 17:00:26 -07:00
* @ param array $safe_strings
* A list of safe strings as previously retrieved by self :: getAll () .
2015-09-04 13:20:09 -07:00
* Every string in this list will be represented by a multidimensional
* array in which the keys are the string and the escaping strategy used for
* this string , and in which the value is the boolean TRUE .
* See self :: isSafe () for the list of supported escaping strategies .
2015-08-17 17:00:26 -07:00
*
* @ throws \UnexpectedValueException
2015-09-04 13:20:09 -07:00
*
* @ internal This is called by FormCache , StringTranslation and the Batch API .
* It should not be used anywhere else .
2015-08-17 17:00:26 -07:00
*/
public static function setMultiple ( array $safe_strings ) {
foreach ( $safe_strings as $string => $strategies ) {
foreach ( $strategies as $strategy => $value ) {
$string = ( string ) $string ;
if ( $value === TRUE ) {
static :: $safeStrings [ $string ][ $strategy ] = TRUE ;
}
else {
// Danger - something is very wrong.
throw new \UnexpectedValueException ( 'Only the value TRUE is accepted for safe strings' );
}
}
}
}
/**
* Gets all strings currently marked as safe .
*
* This is useful for the batch and form APIs , where it is important to
* preserve the safe markup state across page requests .
*
* @ return array
* An array of strings currently marked safe .
*/
public static function getAll () {
return static :: $safeStrings ;
}
/**
* Encodes special characters in a plain - text string for display as HTML .
*
* Also validates strings as UTF - 8. All processed strings are also
* automatically flagged as safe markup strings for rendering .
*
* @ param string $text
* The text to be checked or processed .
*
* @ return string
* An HTML safe version of $text , or an empty string if $text is not valid
* UTF - 8.
*
* @ ingroup sanitization
*
2015-09-04 13:20:09 -07:00
* @ deprecated Will be removed before Drupal 8.0 . 0. Rely on Twig ' s
* auto - escaping feature , or use the @ link theme_render #plain_text @endlink
* key when constructing a render array that contains plain text in order to
* use the renderer ' s auto - escaping feature . If neither of these are
* possible , \Drupal\Component\Utility\Html :: escape () can be used in places
* where explicit escaping is needed .
*
2015-08-17 17:00:26 -07:00
* @ see drupal_validate_utf8 ()
*/
public static function checkPlain ( $text ) {
2015-09-04 13:20:09 -07:00
$string = Html :: escape ( $text );
2015-08-17 17:00:26 -07:00
static :: $safeStrings [ $string ][ 'html' ] = TRUE ;
return $string ;
}
/**
* Formats a string for HTML display by replacing variable placeholders .
*
* This function replaces variable placeholders in a string with the requested
* values and escapes the values so they can be safely displayed as HTML . It
* should be used on any unknown text that is intended to be printed to an
* HTML page ( especially text that may have come from untrusted users , since
* in that case it prevents cross - site scripting and other security problems ) .
*
* In most cases , you should use t () rather than calling this function
* directly , since it will translate the text ( on non - English - only sites ) in
* addition to formatting it .
*
* @ param string $string
* A string containing placeholders . The string itself is not escaped , any
* unsafe content must be in $args and inserted via placeholders .
* @ param array $args
* An associative array of replacements to make . Occurrences in $string of
* any key in $args are replaced with the corresponding value , after
* optional sanitization and formatting . The type of sanitization and
* formatting depends on the first character of the key :
* - @ variable : Escaped to HTML using self :: escape () . Use this as the
* default choice for anything displayed on a page on the site .
2015-09-04 13:20:09 -07:00
* - % variable : Escaped to HTML wrapped in < em > tags , which makes the
* following HTML code :
2015-08-17 17:00:26 -07:00
* @ code
* < em class = " placeholder " > text output here .</ em >
* @ endcode
* - ! variable : Inserted as is , with no sanitization or formatting . Only
* use this when the resulting string is being generated for one of :
* - Non - HTML usage , such as a plain - text email .
* - Non - direct HTML output , such as a plain - text variable that will be
* printed as an HTML attribute value and therefore formatted with
* self :: checkPlain () as part of that .
* - Some other special reason for suppressing sanitization .
*
* @ return string
* The formatted string , which is marked as safe unless sanitization of an
* unsafe argument was suppressed ( see above ) .
*
* @ ingroup sanitization
*
* @ see t ()
*/
2015-09-04 13:20:09 -07:00
public static function format ( $string , array $args ) {
2015-08-17 17:00:26 -07:00
$safe = TRUE ;
// Transform arguments before inserting them.
foreach ( $args as $key => $value ) {
switch ( $key [ 0 ]) {
case '@' :
// Escaped only.
2015-09-04 13:20:09 -07:00
if ( ! SafeMarkup :: isSafe ( $value )) {
$args [ $key ] = Html :: escape ( $value );
}
2015-08-17 17:00:26 -07:00
break ;
case '%' :
default :
// Escaped and placeholder.
2015-09-04 13:20:09 -07:00
if ( ! SafeMarkup :: isSafe ( $value )) {
$value = Html :: escape ( $value );
}
$args [ $key ] = '<em class="placeholder">' . $value . '</em>' ;
2015-08-17 17:00:26 -07:00
break ;
case '!' :
// Pass-through.
if ( ! static :: isSafe ( $value )) {
$safe = FALSE ;
}
}
}
$output = strtr ( $string , $args );
if ( $safe ) {
static :: $safeStrings [ $output ][ 'html' ] = TRUE ;
}
return $output ;
}
}