Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. HeaderUtils.php

class HeaderUtils

HTTP header utility functions.

@author Christian Schmidt <github@chsc.dk>

Hierarchy

  • class \Symfony\Component\HttpFoundation\HeaderUtils

Expanded class hierarchy of HeaderUtils

File

vendor/symfony/http-foundation/HeaderUtils.php, line 19

Namespace

Symfony\Component\HttpFoundation
View source
class HeaderUtils {
    public const DISPOSITION_ATTACHMENT = 'attachment';
    public const DISPOSITION_INLINE = 'inline';
    
    /**
     * This class should not be instantiated.
     */
    private function __construct() {
    }
    
    /**
     * Splits an HTTP header by one or more separators.
     *
     * Example:
     *
     *     HeaderUtils::split('da, en-gb;q=0.8', ',;')
     *     # returns [['da'], ['en-gb', 'q=0.8']]
     *
     * @param string $separators List of characters to split on, ordered by
     *                           precedence, e.g. ',', ';=', or ',;='
     *
     * @return array Nested array with as many levels as there are characters in
     *               $separators
     */
    public static function split(string $header, string $separators) : array {
        if ('' === $separators) {
            throw new \InvalidArgumentException('At least one separator must be specified.');
        }
        $quotedSeparators = preg_quote($separators, '/');
        preg_match_all('
            /
                (?!\\s)
                    (?:
                        # quoted-string
                        "(?:[^"\\\\]|\\\\.)*(?:"|\\\\|$)
                    |
                        # token
                        [^"' . $quotedSeparators . ']+
                    )+
                (?<!\\s)
            |
                # separator
                \\s*
                (?<separator>[' . $quotedSeparators . '])
                \\s*
            /x', trim($header), $matches, \PREG_SET_ORDER);
        return self::groupParts($matches, $separators);
    }
    
    /**
     * Combines an array of arrays into one associative array.
     *
     * Each of the nested arrays should have one or two elements. The first
     * value will be used as the keys in the associative array, and the second
     * will be used as the values, or true if the nested array only contains one
     * element. Array keys are lowercased.
     *
     * Example:
     *
     *     HeaderUtils::combine([['foo', 'abc'], ['bar']])
     *     // => ['foo' => 'abc', 'bar' => true]
     */
    public static function combine(array $parts) : array {
        $assoc = [];
        foreach ($parts as $part) {
            $name = strtolower($part[0]);
            $value = $part[1] ?? true;
            $assoc[$name] = $value;
        }
        return $assoc;
    }
    
    /**
     * Joins an associative array into a string for use in an HTTP header.
     *
     * The key and value of each entry are joined with '=', and all entries
     * are joined with the specified separator and an additional space (for
     * readability). Values are quoted if necessary.
     *
     * Example:
     *
     *     HeaderUtils::toString(['foo' => 'abc', 'bar' => true, 'baz' => 'a b c'], ',')
     *     // => 'foo=abc, bar, baz="a b c"'
     */
    public static function toString(array $assoc, string $separator) : string {
        $parts = [];
        foreach ($assoc as $name => $value) {
            if (true === $value) {
                $parts[] = $name;
            }
            else {
                $parts[] = $name . '=' . self::quote($value);
            }
        }
        return implode($separator . ' ', $parts);
    }
    
    /**
     * Encodes a string as a quoted string, if necessary.
     *
     * If a string contains characters not allowed by the "token" construct in
     * the HTTP specification, it is backslash-escaped and enclosed in quotes
     * to match the "quoted-string" construct.
     */
    public static function quote(string $s) : string {
        if (preg_match('/^[a-z0-9!#$%&\'*.^_`|~-]+$/i', $s)) {
            return $s;
        }
        return '"' . addcslashes($s, '"\\"') . '"';
    }
    
    /**
     * Decodes a quoted string.
     *
     * If passed an unquoted string that matches the "token" construct (as
     * defined in the HTTP specification), it is passed through verbatim.
     */
    public static function unquote(string $s) : string {
        return preg_replace('/\\\\(.)|"/', '$1', $s);
    }
    
    /**
     * Generates an HTTP Content-Disposition field-value.
     *
     * @param string $disposition      One of "inline" or "attachment"
     * @param string $filename         A unicode string
     * @param string $filenameFallback A string containing only ASCII characters that
     *                                 is semantically equivalent to $filename. If the filename is already ASCII,
     *                                 it can be omitted, or just copied from $filename
     *
     * @throws \InvalidArgumentException
     *
     * @see RFC 6266
     */
    public static function makeDisposition(string $disposition, string $filename, string $filenameFallback = '') : string {
        if (!\in_array($disposition, [
            self::DISPOSITION_ATTACHMENT,
            self::DISPOSITION_INLINE,
        ])) {
            throw new \InvalidArgumentException(\sprintf('The disposition must be either "%s" or "%s".', self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE));
        }
        if ('' === $filenameFallback) {
            $filenameFallback = $filename;
        }
        // filenameFallback is not ASCII.
        if (!preg_match('/^[\\x20-\\x7e]*$/', $filenameFallback)) {
            throw new \InvalidArgumentException('The filename fallback must only contain ASCII characters.');
        }
        // percent characters aren't safe in fallback.
        if (str_contains($filenameFallback, '%')) {
            throw new \InvalidArgumentException('The filename fallback cannot contain the "%" character.');
        }
        // path separators aren't allowed in either.
        if (str_contains($filename, '/') || str_contains($filename, '\\') || str_contains($filenameFallback, '/') || str_contains($filenameFallback, '\\')) {
            throw new \InvalidArgumentException('The filename and the fallback cannot contain the "/" and "\\" characters.');
        }
        $params = [
            'filename' => $filenameFallback,
        ];
        if ($filename !== $filenameFallback) {
            $params['filename*'] = "utf-8''" . rawurlencode($filename);
        }
        return $disposition . '; ' . self::toString($params, ';');
    }
    
    /**
     * Like parse_str(), but preserves dots in variable names.
     */
    public static function parseQuery(string $query, bool $ignoreBrackets = false, string $separator = '&') : array {
        $q = [];
        foreach (explode($separator, $query) as $v) {
            if (false !== ($i = strpos($v, "\x00"))) {
                $v = substr($v, 0, $i);
            }
            if (false === ($i = strpos($v, '='))) {
                $k = urldecode($v);
                $v = '';
            }
            else {
                $k = urldecode(substr($v, 0, $i));
                $v = substr($v, $i);
            }
            if (false !== ($i = strpos($k, "\x00"))) {
                $k = substr($k, 0, $i);
            }
            $k = ltrim($k, ' ');
            if ($ignoreBrackets) {
                $q[$k][] = urldecode(substr($v, 1));
                continue;
            }
            if (false === ($i = strpos($k, '['))) {
                $q[] = bin2hex($k) . $v;
            }
            else {
                $q[] = bin2hex(substr($k, 0, $i)) . rawurlencode(substr($k, $i)) . $v;
            }
        }
        if ($ignoreBrackets) {
            return $q;
        }
        parse_str(implode('&', $q), $q);
        $query = [];
        foreach ($q as $k => $v) {
            if (false !== ($i = strpos($k, '_'))) {
                $query[substr_replace($k, hex2bin(substr($k, 0, $i)) . '[', 0, 1 + $i)] = $v;
            }
            else {
                $query[hex2bin($k)] = $v;
            }
        }
        return $query;
    }
    private static function groupParts(array $matches, string $separators, bool $first = true) : array {
        $separator = $separators[0];
        $separators = substr($separators, 1) ?: '';
        $i = 0;
        if ('' === $separators && !$first) {
            $parts = [
                '',
            ];
            foreach ($matches as $match) {
                if (!$i && isset($match['separator'])) {
                    $i = 1;
                    $parts[1] = '';
                }
                else {
                    $parts[$i] .= self::unquote($match[0]);
                }
            }
            return $parts;
        }
        $parts = [];
        $partMatches = [];
        foreach ($matches as $match) {
            if (($match['separator'] ?? null) === $separator) {
                ++$i;
            }
            else {
                $partMatches[$i][] = $match;
            }
        }
        foreach ($partMatches as $matches) {
            if ('' === $separators && '' !== ($unquoted = self::unquote($matches[0][0]))) {
                $parts[] = $unquoted;
            }
            elseif ($groupedParts = self::groupParts($matches, $separators, false)) {
                $parts[] = $groupedParts;
            }
        }
        return $parts;
    }

}

Members

Title Sort descending Modifiers Object type Summary
HeaderUtils::combine public static function Combines an array of arrays into one associative array.
HeaderUtils::DISPOSITION_ATTACHMENT public constant
HeaderUtils::DISPOSITION_INLINE public constant
HeaderUtils::groupParts private static function
HeaderUtils::makeDisposition public static function Generates an HTTP Content-Disposition field-value.
HeaderUtils::parseQuery public static function Like parse_str(), but preserves dots in variable names.
HeaderUtils::quote public static function Encodes a string as a quoted string, if necessary.
HeaderUtils::split public static function Splits an HTTP header by one or more separators.
HeaderUtils::toString public static function Joins an associative array into a string for use in an HTTP header.
HeaderUtils::unquote public static function Decodes a quoted string.
HeaderUtils::__construct private function This class should not be instantiated.

API Navigation

  • Drupal Core 11.1.x
  • Topics
  • Classes
  • Functions
  • Constants
  • Globals
  • Files
  • Namespaces
  • Deprecated
  • Services
RSS feed
Powered by Drupal