'); * @endcode * * @param string $string * The content to be marked as secure. * @param string $strategy * The escaping strategy used for this string. Two values are supported * by default: * - '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 string * The input string that was marked as safe. */ public static function set($string, $strategy = 'html') { $string = (string) $string; static::$safeStrings[$string][$strategy] = TRUE; return $string; } /** * Checks if a string is safe to output. * * @param string|\Drupal\Component\Utility\SafeStringInterface $string * The content to be checked. * @param string $strategy * The escaping strategy. See self::set(). Defaults to 'html'. * * @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. * * This is useful for the batch and form APIs, where it is important to * preserve the safe markup state across page requests. The strings will be * added to any safe strings already marked for the current request. * * @param array $safe_strings * A list of safe strings as previously retrieved by self::getAll(). * * @throws \UnexpectedValueException */ 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'); } } } } /** * Encodes special characters in a plain-text string for display as HTML. * * @param string $string * A string. * * @return string * The escaped string. If $string was already set as safe with * self::set(), it won't be escaped again. */ public static function escape($string) { return static::isSafe($string) ? $string : static::checkPlain($string); } /** * Applies a very permissive XSS/HTML filter for admin-only use. * * @param string $string * A string. * * @return string * The escaped string. If $string was already set as safe with * self::set(), it won't be escaped again. * * @see \Drupal\Component\Utility\Xss::filterAdmin() */ public static function checkAdminXss($string) { return static::isSafe($string) ? $string : Xss::filterAdmin($string); } /** * 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 * * @see drupal_validate_utf8() */ public static function checkPlain($text) { $string = htmlspecialchars($text, ENT_QUOTES, 'UTF-8'); 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. * - %variable: Escaped to HTML and formatted using self::placeholder(), * which makes the following HTML code: * @code * text output here. * @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() */ public static function format($string, array $args = array()) { $safe = TRUE; // Transform arguments before inserting them. foreach ($args as $key => $value) { switch ($key[0]) { case '@': // Escaped only. $args[$key] = static::escape($value); break; case '%': default: // Escaped and placeholder. $args[$key] = static::placeholder($value); break; case '!': // Pass-through. if (!static::isSafe($value)) { $safe = FALSE; } } } $output = strtr($string, $args); if ($safe) { static::$safeStrings[$output]['html'] = TRUE; } return $output; } /** * Formats text for emphasized display in a placeholder inside a sentence. * * Used automatically by self::format(). * * @param string $text * The text to format (plain-text). * * @return string * The formatted text (html). */ public static function placeholder($text) { $string = '' . static::escape($text) . ''; static::$safeStrings[$string]['html'] = TRUE; return $string; } /** * Replaces all occurrences of the search string with the replacement string. * * Functions identically to str_replace(), but marks the returned output as * safe if all the inputs and the subject have also been marked as safe. * * @param string|array $search * The value being searched for. An array may be used to designate multiple * values to search for. * @param string|array $replace * The replacement value that replaces found search values. An array may be * used to designate multiple replacements. * @param string $subject * The string or array being searched and replaced on. * * @return string * The passed subject with replaced values. */ public static function replace($search, $replace, $subject) { $output = str_replace($search, $replace, $subject); // If any replacement is unsafe, then the output is also unsafe, so just // return the output. if (!is_array($replace)) { if (!SafeMarkup::isSafe($replace)) { return $output; } } else { foreach ($replace as $replacement) { if (!SafeMarkup::isSafe($replacement)) { return $output; } } } // If the subject is unsafe, then the output is as well, so return it. if (!SafeMarkup::isSafe($subject)) { return $output; } else { // If we have reached this point, then all replacements were safe. If the // subject was also safe, then mark the entire output as safe. return SafeMarkup::set($output); } } }