protected static function FormattableMarkup::placeholderFormat in Drupal 8
Same name and namespace in other branches
- 9 core/lib/Drupal/Component/Render/FormattableMarkup.php \Drupal\Component\Render\FormattableMarkup::placeholderFormat()
Replaces placeholders in a string with values.
Parameters
string $string: A string containing placeholders. The string itself is expected to be safe and correct HTML. Any unsafe content must be in $args and inserted via placeholders.
array $args: An associative array of replacements. Each array key should be the same as a placeholder in $string. The corresponding value should be a string or an object that implements \Drupal\Component\Render\MarkupInterface. The value replaces the placeholder in $string. Sanitization and formatting will be done before replacement. The type of sanitization and formatting depends on the first character of the key:
- @variable: When the placeholder replacement value is:
- A string, the replaced value in the returned string will be sanitized using \Drupal\Component\Utility\Html::escape().
- A MarkupInterface object, the replaced value in the returned string will not be sanitized.
- A MarkupInterface object cast to a string, the replaced value in the returned string be forcibly sanitized using \Drupal\Component\Utility\Html::escape().
$this->placeholderFormat('This will force HTML-escaping of the replacement value: @text', ['@text' => (string) $safe_string_interface_object));
Use this placeholder as the default choice for anything displayed on the site, but not within HTML attributes, JavaScript, or CSS. Doing so is a security risk.
- %variable: Use when the replacement value is to be wrapped in <em> tags. A call like:
$string = "%output_text";
$arguments = [
'%output_text' => 'text output here.',
];
$this
->placeholderFormat($string, $arguments);
makes the following HTML code:
<em class="placeholder">text output here.</em>
As with @variable, do not use this within HTML attributes, JavaScript, or CSS. Doing so is a security risk.
- :variable: Return value is escaped with \Drupal\Component\Utility\Html::escape() and filtered for dangerous protocols using UrlHelper::stripDangerousProtocols(). Use this when using the "href" attribute, ensuring the attribute value is always wrapped in quotes:
// Secure (with quotes):
$this
->placeholderFormat('<a href=":url">@variable</a>', [
':url' => $url,
'@variable' => $variable,
]);
// Insecure (without quotes):
$this
->placeholderFormat('<a href=:url>@variable</a>', [
':url' => $url,
'@variable' => $variable,
]);
When ":variable" comes from arbitrary user input, the result is secure, but not guaranteed to be a valid URL (which means the resulting output could fail HTML validation). To guarantee a valid URL, use Url::fromUri($user_input)->toString() (which either throws an exception or returns a well-formed URL) before passing the result into a ":variable" placeholder.
Return value
string A formatted HTML string with the placeholders replaced.
See also
\Drupal\Core\StringTranslation\TranslatableMarkup
\Drupal\Core\StringTranslation\PluralTranslatableMarkup
\Drupal\Component\Utility\Html::escape()
\Drupal\Component\Utility\UrlHelper::stripDangerousProtocols()
Related topics
3 calls to FormattableMarkup::placeholderFormat()
- FormattableMarkup::__toString in core/
lib/ Drupal/ Component/ Render/ FormattableMarkup.php - Returns markup.
- PluralTranslatableMarkup::render in core/
lib/ Drupal/ Core/ StringTranslation/ PluralTranslatableMarkup.php - Renders the object as a string.
- TranslatableMarkup::render in core/
lib/ Drupal/ Core/ StringTranslation/ TranslatableMarkup.php - Renders the object as a string.
File
- core/
lib/ Drupal/ Component/ Render/ FormattableMarkup.php, line 194
Class
- FormattableMarkup
- Formats a string for HTML display by replacing variable placeholders.
Namespace
Drupal\Component\RenderCode
protected static function placeholderFormat($string, array $args) {
// Transform arguments before inserting them.
foreach ($args as $key => $value) {
switch ($key[0]) {
case '@':
// Escape if the value is not an object from a class that implements
// \Drupal\Component\Render\MarkupInterface, for example strings will
// be escaped.
// Strings that are safe within HTML fragments, but not within other
// contexts, may still be an instance of
// \Drupal\Component\Render\MarkupInterface, so this placeholder type
// must not be used within HTML attributes, JavaScript, or CSS.
$args[$key] = static::placeholderEscape($value);
break;
case ':':
// Strip URL protocols that can be XSS vectors.
$value = UrlHelper::stripDangerousProtocols($value);
// Escape unconditionally, without checking whether the value is an
// instance of \Drupal\Component\Render\MarkupInterface. This forces
// characters that are unsafe for use in an "href" HTML attribute to
// be encoded. If a caller wants to pass a value that is extracted
// from HTML and therefore is already HTML encoded, it must invoke
// \Drupal\Component\Render\OutputStrategyInterface::renderFromHtml()
// on it prior to passing it in as a placeholder value of this type.
// @todo Add some advice and stronger warnings.
// https://www.drupal.org/node/2569041.
$args[$key] = Html::escape($value);
break;
case '%':
// Similarly to @, escape non-safe values. Also, add wrapping markup
// in order to render as a placeholder. Not for use within attributes,
// per the warning above about
// \Drupal\Component\Render\MarkupInterface and also due to the
// wrapping markup.
$args[$key] = '<em class="placeholder">' . static::placeholderEscape($value) . '</em>';
break;
default:
// We do not trigger an error for placeholder that start with an
// alphabetic character.
// @todo https://www.drupal.org/node/2807743 Change to an exception
// and always throw regardless of the first character.
if (!ctype_alpha($key[0])) {
// We trigger an error as we may want to introduce new placeholders
// in the future without breaking backward compatibility.
trigger_error('Invalid placeholder (' . $key . ') in string: ' . $string, E_USER_ERROR);
}
elseif (strpos($string, $key) !== FALSE) {
trigger_error('Invalid placeholder (' . $key . ') in string: ' . $string, E_USER_DEPRECATED);
}
// No replacement possible therefore we can discard the argument.
unset($args[$key]);
break;
}
}
return strtr($string, $args);
}