0 follower

Final Class Yiisoft\Http\HeaderValueHelper

InheritanceYiisoft\Http\HeaderValueHelper

HeaderValueHelper parses the header value parameters.

Public Methods

Hide inherited methods

Method Description Defined By
getParameters() Explodes a header value parameters (eg. q=2;version=6) Yiisoft\Http\HeaderValueHelper
getSortedAcceptTypes() Returns a list of sorted content types from the accept header values. Yiisoft\Http\HeaderValueHelper
getSortedValueAndParameters() Returns a header value as "q" factor sorted list. Yiisoft\Http\HeaderValueHelper
getValueAndParameters() Explodes a header value to value and parameters (eg. text/html;q=2;version=6) Yiisoft\Http\HeaderValueHelper

Constants

Hide inherited constants

Constant Value Description Defined By
PATTERN_ATTRIBUTE self::PATTERN_TOKEN Yiisoft\Http\HeaderValueHelper
PATTERN_QUOTED_STRING '(?:"(?:(?:\\\.)+|[^\"]+)*")' Yiisoft\Http\HeaderValueHelper
PATTERN_TOKEN '(?:(?:[^()<>@,;:\"\/[\]?={} \t\x7f]|[\x00-\x1f])+)' Yiisoft\Http\HeaderValueHelper
PATTERN_VALUE '(?:' . self::PATTERN_QUOTED_STRING . '|' . self::PATTERN_TOKEN . ')' Yiisoft\Http\HeaderValueHelper

Method Details

Hide inherited methods

getParameters() public static method

Explodes a header value parameters (eg. q=2;version=6)

public static string[] getParameters ( string $headerValueParameters, boolean $lowerCaseParameter true, boolean $lowerCaseParameterValue true )
$headerValueParameters string

Header value parameters.

$lowerCaseParameter boolean

Whether should cast header parameter name to lowercase.

$lowerCaseParameterValue boolean

Whether should cast header parameter value to lowercase.

return string[]

Key-value are the parameters.

                public static function getParameters(
    string $headerValueParameters,
    bool $lowerCaseParameter = true,
    bool $lowerCaseParameterValue = true
): array {
    $headerValueParameters = trim($headerValueParameters);
    if ($headerValueParameters === '') {
        return [];
    }
    if (rtrim($headerValueParameters, ';') !== $headerValueParameters) {
        throw new InvalidArgumentException('Cannot end with a semicolon.');
    }
    $output = [];
    do {
        /**
         * @var string $headerValueParameters We use valid regular expression, so `preg_replace()` always returns string.
         */
        $headerValueParameters = preg_replace_callback(
            '/^[ \t]*(?<parameter>' . self::PATTERN_ATTRIBUTE . ')[ \t]*=[ \t]*(?<value>' . self::PATTERN_VALUE . ')[ \t]*(?:;|$)/u',
            static function (array $matches) use (&$output, $lowerCaseParameter, $lowerCaseParameterValue): string {
                $value = $matches['value'];
                if (mb_strpos($matches['value'], '"') === 0) {
                    /**
                     * Unescape + Remove first and last quote
                     *
                     * @var string $value We use valid regular expression, so `preg_replace()` always returns string.
                     */
                    $value = preg_replace('/\\\\(.)/u', '$1', mb_substr($value, 1, -1));
                }
                $key = $lowerCaseParameter ? mb_strtolower($matches['parameter']) : $matches['parameter'];
                if (isset($output[$key])) {
                    // The first is the winner.
                    return '';
                }
                /** @psalm-suppress MixedArrayAssignment False-positive error */
                $output[$key] = $lowerCaseParameterValue ? mb_strtolower($value) : $value;
                return '';
            },
            $headerValueParameters,
            1,
            $count
        );
        if ($count !== 1) {
            throw new InvalidArgumentException('Invalid input: ' . $headerValueParameters);
        }
    } while ($headerValueParameters !== '');
    /** @var array<string,string> $output */
    return $output;
}

            
getSortedAcceptTypes() public static method

Returns a list of sorted content types from the accept header values.

public static string[] getSortedAcceptTypes ( string|string[] $values )
$values string|string[]

Header value as a comma-separated string or already exploded string array.

return string[]

Sorted accept types. Note: According to RFC 7231, special parameters (except the q factor) are added to the type, which are always appended by a semicolon and sorted by string.

                public static function getSortedAcceptTypes($values): array
{
    $output = self::getSortedValueAndParameters($values);
    usort($output, static function (array $a, array $b) {
        /**
         * @psalm-var QFactorHeader $a
         * @psalm-var QFactorHeader $b
         */
        if ($a['q'] !== $b['q']) {
            // The higher q value wins
            return $a['q'] > $b['q'] ? -1 : 1;
        }
        /** @var string $typeA */
        $typeA = reset($a);
        /** @var string $typeB */
        $typeB = reset($b);
        if (strpos($typeA, '*') === false && strpos($typeB, '*') === false) {
            $countA = count($a);
            $countB = count($b);
            if ($countA === $countB) {
                // They are equivalent for the same parameter number
                return 0;
            }
            // No wildcard character, higher parameter number wins
            return $countA > $countB ? -1 : 1;
        }
        $endWildcardA = substr($typeA, -1, 1) === '*';
        $endWildcardB = substr($typeB, -1, 1) === '*';
        if (($endWildcardA && !$endWildcardB) || (!$endWildcardA && $endWildcardB)) {
            // The wildcard ends is the loser.
            return $endWildcardA ? 1 : -1;
        }
        // The wildcard starts is the loser.
        return strpos($typeA, '*') === 0 ? 1 : -1;
    });
    foreach ($output as $key => $value) {
        $type = array_shift($value);
        unset($value['q']);
        if (count($value) === 0) {
            $output[$key] = $type;
            continue;
        }
        foreach ($value as $k => $v) {
            $value[$k] = $k . '=' . $v;
        }
        // Parameters are sorted for easier use of parameter variations.
        asort($value, SORT_STRING);
        $output[$key] = $type . ';' . implode(';', $value);
    }
    /** @var string[] $output */
    return $output;
}

            
getSortedValueAndParameters() public static method

Returns a header value as "q" factor sorted list.

See also getValueAndParameters().

public static array[] getSortedValueAndParameters ( string|string[] $values, boolean $lowerCaseValue true, boolean $lowerCaseParameter true, boolean $lowerCaseParameterValue true )
$values string|string[]

Header value as a comma-separated string or already exploded string array.

$lowerCaseValue boolean

Whether should cast header value to lowercase.

$lowerCaseParameter boolean

Whether should cast header parameter name to lowercase.

$lowerCaseParameterValue boolean

Whether should cast header parameter value to lowercase.

return array[]

The q factor sorted list.

                public static function getSortedValueAndParameters(
    $values,
    bool $lowerCaseValue = true,
    bool $lowerCaseParameter = true,
    bool $lowerCaseParameterValue = true
): array {
    /** @var mixed $values Don't trust to annotations. */
    if (!is_array($values) && !is_string($values)) {
        throw new InvalidArgumentException('Values are neither array nor string.');
    }
    $list = [];
    foreach ((array) $values as $headerValue) {
        if (!is_string($headerValue)) {
            throw new InvalidArgumentException('Values must be array of strings.');
        }
        /** @psalm-suppress InvalidOperand Presume that `preg_split` never returns false here. */
        $list = [...$list, ...preg_split('/\s*,\s*/', trim($headerValue), -1, PREG_SPLIT_NO_EMPTY)];
    }
    /** @var string[] $list */
    if (count($list) === 0) {
        return [];
    }
    $output = [];
    foreach ($list as $value) {
        $parse = self::getValueAndParameters(
            $value,
            $lowerCaseValue,
            $lowerCaseParameter,
            $lowerCaseParameterValue
        );
        // case-insensitive "q" parameter
        $q = $parse['q'] ?? $parse['Q'] ?? 1.0;
        // min 0.000 max 1.000, max 3 digits, without digits allowed
        if (is_string($q) && preg_match('/^(?:0(?:\.\d{1,3})?|1(?:\.0{1,3})?)$/', $q) === 0) {
            throw new InvalidArgumentException('Invalid q factor.');
        }
        $parse['q'] = (float) $q;
        unset($parse['Q']);
        $output[] = $parse;
    }
    usort(
        $output,
        static function (array $a, array $b) {
            return $b['q'] <=> $a['q'];
        }
    );
    return $output;
}

            
getValueAndParameters() public static method

Explodes a header value to value and parameters (eg. text/html;q=2;version=6)

public static string[] getValueAndParameters ( string $headerValue, boolean $lowerCaseValue true, boolean $lowerCaseParameter true, boolean $lowerCaseParameterValue true )
$headerValue string

Header value.

$lowerCaseValue boolean

Whether should cast header value to lowercase.

$lowerCaseParameter boolean

Whether should cast header parameter name to lowercase.

$lowerCaseParameterValue boolean

Whether should cast header parameter value to lowercase.

return string[]

First element is the value, and key-value are the parameters.

                public static function getValueAndParameters(
    string $headerValue,
    bool $lowerCaseValue = true,
    bool $lowerCaseParameter = true,
    bool $lowerCaseParameterValue = true
): array {
    $headerValue = trim($headerValue);
    if ($headerValue === '') {
        return [];
    }
    $parts = explode(';', $headerValue, 2);
    $output = [$lowerCaseValue ? strtolower($parts[0]) : $parts[0]];
    if (count($parts) === 1) {
        return $output;
    }
    /** @psalm-var array{0:string,1:string} $parts */
    return $output + self::getParameters($parts[1], $lowerCaseParameter, $lowerCaseParameterValue);
}