GeneralDirective::fromString()   B
last analyzed

Complexity

Conditions 7
Paths 4

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 7

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 10
c 1
b 0
f 0
nc 4
nop 1
dl 0
loc 19
ccs 11
cts 11
cp 1
crap 7
rs 8.8333
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stadly\Http\Header\Value\CacheControl;
6
7
use InvalidArgumentException;
8
use Stadly\Http\Utilities\Rfc7230;
9
use Stadly\Http\Utilities\Rfc7234;
10
11
/**
12
 * Class for handling cache control directives with optional value.
13
 *
14
 * Specification: https://tools.ietf.org/html/rfc7234#section-5.2.2
15
 */
16
final class GeneralDirective extends Directive
17
{
18
    /**
19
     * @var string|null Value.
20
     */
21
    private $value;
22
23
    /**
24
     * Constructor.
25
     *
26
     * @param string $name Name.
27
     * @param string|null $value Value.
28
     */
29 9
    public function __construct(string $name, ?string $value = null)
30
    {
31 9
        $this->setName($name);
32 4
        $this->setValue($value);
33
    }
34
35
    /**
36
     * Construct directive from string.
37
     *
38
     * @param string $directive Directive string.
39
     * @return self Directive generated based on the string.
40
     */
41 7
    public static function fromString(string $directive): self
42
    {
43 7
        $regEx = '{^' . Rfc7234::CACHE_DIRECTIVE_CAPTURE . '$}';
44 7
        $plainDirective = mb_convert_encoding($directive, 'ISO-8859-1', 'UTF-8');
45 7
        if ($plainDirective !== $directive || preg_match($regEx, $directive, $matches) !== 1) {
46 3
            throw new InvalidArgumentException('Invalid directive: ' . $directive);
47
        }
48
49 4
        if (!isset($matches['VALUE'])) {
50 1
            return new self($matches['NAME'], /*value*/null);
51
        }
52
53 3
        $value = $matches['VALUE'];
54
        // Strip slashes if value is quoted.
55 3
        if (mb_strlen($value) >= 2 && mb_substr($value, 0, 1) === '"' && mb_substr($value, -1) === '"') {
56 2
            $value = stripslashes(mb_substr($value, 1, -1));
57
        }
58
59 3
        return new self($matches['NAME'], $value);
60
    }
61
62
    /**
63
     * @inheritDoc
64
     */
65 4
    public function __toString(): string
66
    {
67 4
        if ($this->value === null) {
68 1
            return $this->name;
69
        }
70
71 3
        return $this->name . '=' . self::encodeValue($this->value);
72
    }
73
74
    /**
75
     * @param string $name Name.
76
     */
77 6
    public function setName(string $name): void
78
    {
79 6
        $plainName = mb_convert_encoding($name, 'ISO-8859-1', 'UTF-8');
80 6
        if ($plainName !== $name || preg_match('{^' . Rfc7230::TOKEN . '$}', $name) !== 1) {
81 2
            throw new InvalidArgumentException('Invalid name: ' . $name);
82
        }
83
84 6
        if (in_array(strtolower($name), FieldListDirective::RESERVED_NAMES, /*strict*/true)) {
85 1
            throw new InvalidArgumentException('Name reserved for field list directive: ' . $name);
86
        }
87 6
        if (in_array(strtolower($name), IntegerDirective::RESERVED_NAMES, /*strict*/true)) {
88 1
            throw new InvalidArgumentException('Name reserved for integer directive: ' . $name);
89
        }
90 6
        if (in_array(strtolower($name), ValuelessDirective::RESERVED_NAMES, /*strict*/true)) {
91 1
            throw new InvalidArgumentException('Name reserved for valueless directive: ' . $name);
92
        }
93
94 6
        $this->name = $name;
95
    }
96
97
    /**
98
     * @inheritDoc
99
     */
100 1
    public function getValue(): ?string
101
    {
102 1
        return $this->value;
103
    }
104
105
    /**
106
     * @param string|null $value Value.
107
     */
108 5
    public function setValue(?string $value): void
109
    {
110 5
        if ($value !== null) {
111 5
            $encodedValue = self::encodeValue($value);
112
113 5
            $regEx = '{^(?:' . Rfc7230::TOKEN . '|' . Rfc7230::QUOTED_STRING . ')$}';
114 5
            $plainValue = mb_convert_encoding($encodedValue, 'ISO-8859-1', 'UTF-8');
115 5
            if ($plainValue !== $encodedValue || preg_match($regEx, $encodedValue) !== 1) {
116 1
                throw new InvalidArgumentException('Invalid value: ' . $value);
117
            }
118
        }
119
120 5
        $this->value = $value;
121
    }
122
123
    /**
124
     * @param string $value Value.
125
     * @return string Encoded value.
126
     */
127 22
    private static function encodeValue(string $value): string
128
    {
129 22
        if (preg_match('{^' . Rfc7230::TOKEN . '$}', $value) === 1) {
130 16
            return $value;
131
        }
132
133
        // If value is not a valid token, turn it into a quoted token.
134 9
        return '"' . addslashes($value) . '"';
135
    }
136
}
137