function FormattableMarkup::placeholderFormat

Same name and namespace in other branches
  1. 8.9.x core/lib/Drupal/Component/Render/FormattableMarkup.php \Drupal\Component\Render\FormattableMarkup::placeholderFormat()
  2. 10 core/lib/Drupal/Component/Render/FormattableMarkup.php \Drupal\Component\Render\FormattableMarkup::placeholderFormat()
  3. 11.x 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. Null args[] values are deprecated in Drupal 9.5 and will fail in Drupal 11.0. 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:


        $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()

\Drupal\Core\Url::fromUri()

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 196

Class

FormattableMarkup
Formats a string for HTML display by replacing variable placeholders.

Namespace

Drupal\Component\Render

Code

protected static function placeholderFormat($string, array $args) {
    // Transform arguments before inserting them.
    foreach ($args as $key => $value) {
        if (is_null($value)) {
            // It's probably a bug to provide a null value for the placeholder arg,
            // and in D11 this will no longer be allowed. When this trigger_error
            // is removed, also remove isset $value checks inside the switch{}
            // below.
            @trigger_error(sprintf('Deprecated NULL placeholder value for key (%s) in: "%s". This will throw a PHP error in drupal:11.0.0. See https://www.drupal.org/node/3318826', (string) $key, (string) $string), E_USER_DEPRECATED);
            $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:
                // Deprecate support for random variables that won't be replaced.
                if (ctype_alpha($key[0]) && strpos($string, $key) === FALSE) {
                    @trigger_error(sprintf('Support for keys without a placeholder prefix is deprecated in Drupal 9.1.0 and will be removed in Drupal 10.0.0. Invalid placeholder (%s) with string: "%s"', $key, $string), E_USER_DEPRECATED);
                }
                else {
                    trigger_error(sprintf('Invalid placeholder (%s) with string: "%s"', $key, $string), E_USER_WARNING);
                }
                // No replacement possible therefore we can discard the argument.
                unset($args[$key]);
                break;
        }
    }
    return strtr($string, $args);
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.