-
Notifications
You must be signed in to change notification settings - Fork 0
/
CurlOptionCollection.php
158 lines (138 loc) · 4.8 KB
/
CurlOptionCollection.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
<?php
declare(strict_types=1);
namespace MicroDeps\Curl;
use InvalidArgumentException;
/**
* @phpstan-type phpstanCurlOption array<int|string,int|string>|bool|float|int|resource|string
* @phpstan-type phpstanCurlOptions array<int, phpstanCurlOption>
*/
final class CurlOptionCollection
{
public const OPTIONS_DEFAULT = [
/*
* true to follow any 'Location: ' header that the server sends as part of the HTTP header.
* See also CURLOPT_MAXREDIRS.
*/
CURLOPT_FOLLOWLOCATION => true,
/*
* true to return the transfer as a string of the return value of curl_exec() instead of outputting it directly.
*/
CURLOPT_RETURNTRANSFER => true,
/*
* The contents of the 'Accept-Encoding: ' header. This enables decoding of the response.
* Supported encodings are 'identity', 'deflate', and 'gzip'.
* If an empty string, '', is set, a header containing all supported encoding types is sent.
*/
CURLOPT_ENCODING => '',
/*
* Log the headers that are sent with the initial request and make available via curl_getinfo
*/
CURLINFO_HEADER_OUT => true,
];
/**
* These are special options that don't start with CURLOPT for whatever reason.
*/
private const SPECIAL_OPTS = [
'CURLINFO_HEADER_OUT',
];
/** @var array<int,string> */
private static array $validOptions = [];
/**
* The configuration with constant names for keys instead of ints.
*
* @var array<string, phpstanCurlOption>
*/
private array $optionsDebug = [];
/** @var phpstanCurlOptions */
private $options;
/**
* @param phpstanCurlOptions $options
*/
public function __construct(array $options = self::OPTIONS_DEFAULT)
{
$this->set($options);
}
/** @return array<int,string> */
public static function validOptions(): array
{
if ([] === self::$validOptions) {
$curlOptions = get_defined_constants(true)['curl'];
$curlOptions = array_filter(
$curlOptions,
static fn ($key) => str_starts_with($key, 'CURLOPT_')
|| \in_array($key, self::SPECIAL_OPTS, true),
ARRAY_FILTER_USE_KEY
);
// note, as we do the flip, we aggregate some aliased options.
// There are some options with multiple constants that point to the same int value
/** @var array<int, string> $curlOptions */
$curlOptions = array_flip($curlOptions);
self::$validOptions = $curlOptions;
}
return self::$validOptions;
}
/**
* Set specific options, or call with no arguments to reset to the default.
*
* @param phpstanCurlOptions $options
*/
public function set(array $options = null): self
{
$this->options = $this->optionsDebug = [];
$this->update($options ?? self::OPTIONS_DEFAULT);
return $this;
}
/**
* @param phpstanCurlOptions $options
*
* @throws CurlException
*/
public function update(array $options): self
{
if ([] === $options) {
return $this;
}
self::validOptions();
// note, array_merge won't work due to numeric keys for curl options
$invalid = [];
foreach ($options as $key => $value) {
/* @phpstan-ignore-next-line its user data, we can't guarantee types and need to check */
if (\is_string($key)) {
throw new InvalidArgumentException("
you have set an option with a string key {$key},
instead you should be using teh actual curl constant - not its name as a string
");
}
if (!isset(self::$validOptions[$key])) {
$invalid[$key] = $value;
continue;
}
$this->options[$key] = $value;
$this->optionsDebug[self::$validOptions[$key]] = $value;
}
if ([] !== $invalid) {
throw CurlException::withFormat(
CurlException::MSG_INVALID_OPTIONS,
print_r($invalid, true),
/* @phpstan-ignore-next-line confused by curl_version return type */
curl_version()['version']
);
}
return $this;
}
/** @return phpstanCurlOptions */
public function get(): array
{
return $this->options;
}
/** @return phpstanCurlOption|null */
public function getOption(int $key): mixed
{
return $this->options[$key] ?? null;
}
/** @return array<string, phpstanCurlOption> */
public function getOptionsDebug(): array
{
return $this->optionsDebug;
}
}