• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

webeweb / core-library / 16553382373

27 Jul 2025 04:49PM UTC coverage: 99.806% (-0.03%) from 99.832%
16553382373

push

github

webeweb
Update unit tests

87525 of 87695 relevant lines covered (99.81%)

18.48 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.43
/lib/curl/Request/AbstractRequest.php
1
<?php
2

3
/*
4
 * This file is part of the core-library package.
5
 *
6
 * (c) 2017 WEBEWEB
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11

12
declare(strict_types = 1);
13

14
namespace WBW\Library\Curl\Request;
15

16
use DateTime;
17
use InvalidArgumentException;
18
use WBW\Library\Curl\Configuration\Configuration;
19
use WBW\Library\Curl\Exception\RequestCallException;
20
use WBW\Library\Curl\Factory\CurlFactory;
21
use WBW\Library\Curl\Helper\CurlHelper;
22
use WBW\Library\Curl\Response\Response;
23
use WBW\Library\Curl\Response\ResponseInterface;
24

25
/**
26
 * Abstract request.
27
 *
28
 * @author webeweb <https://github.com/webeweb>
29
 * @package WBW\Library\Curl\Request
30
 * @abstract
31
 */
32
abstract class AbstractRequest implements RequestInterface {
33

34
    /**
35
     * Configuration.
36
     *
37
     * @var Configuration|null
38
     */
39
    private $configuration;
40

41
    /**
42
     * Headers.
43
     *
44
     * @var array<string,string>|null
45
     */
46
    private $headers;
47

48
    /**
49
     * Method.
50
     *
51
     * @var string|null
52
     */
53
    private $method;
54

55
    /**
56
     * POST data.
57
     *
58
     * @var array<string,string>|null
59
     */
60
    private $postData;
61

62
    /**
63
     * Query data.
64
     *
65
     * @var array<string,string>|null
66
     */
67
    private $queryData;
68

69
    /**
70
     * Resource path.
71
     *
72
     * @var string|null
73
     */
74
    private $resourcePath;
75

76
    /**
77
     * Constructor.
78
     *
79
     * @param string $method The Method.
80
     * @param Configuration $configuration The configuration.
81
     * @param string|null $resourcePath The resource path.
82
     * @throws InvalidArgumentException Throws an invalid argument exception if the method is invalid.
83
     */
84
    protected function __construct(string $method, Configuration $configuration, ?string $resourcePath) {
85
        $this->setConfiguration($configuration);
198✔
86
        $this->setHeaders([]);
198✔
87
        $this->setMethod($method);
198✔
88
        $this->setQueryData([]);
198✔
89
        $this->setPostData([]);
198✔
90
        $this->setResourcePath($resourcePath);
198✔
91
    }
44✔
92

93
    /**
94
     * {@inheritDoc}
95
     */
96
    public function addHeader(string $name, string $value): RequestInterface {
97
        $this->headers[$name] = $value;
18✔
98
        return $this;
18✔
99
    }
100

101
    /**
102
     * {@inheritDoc}
103
     */
104
    public function addPostData(string $name, string $value): RequestInterface {
105
        $this->postData[$name] = $value;
36✔
106
        return $this;
36✔
107
    }
108

109
    /**
110
     * {@inheritDoc}
111
     */
112
    public function addQueryData(string $name, string $value): RequestInterface {
113
        $this->queryData[$name] = $value;
18✔
114
        return $this;
18✔
115
    }
116

117
    /**
118
     * {@inheritDoc}
119
     */
120
    public function call(): ResponseInterface {
121

122
        $requestHeader = $this->mergeHeaders();
9✔
123
        $requestBody   = http_build_query($this->getPostData());
9✔
124

125
        if (true === in_array("Content-Type: application/json", $requestHeader)) {
9✔
126
            $requestBody = json_encode($this->getPostData());
9✔
127
        }
128

129
        $requestUrl = $this->mergeUrl();
9✔
130
        if (0 < count($this->getQueryData())) {
9✔
131
            $requestUrl = implode("?", [$requestUrl, http_build_query($this->getQueryData())]);
×
132
        }
133

134
        $stream = CurlHelper::initStream($requestUrl, $this->getConfiguration());
9✔
135

136
        CurlHelper::setHeaders($stream, $requestHeader);
9✔
137
        CurlHelper::setPost($stream, $this->getMethod(), $requestBody);
9✔
138
        CurlHelper::setProxy($stream, $this->getConfiguration());
9✔
139
        CurlHelper::setReturnTransfer($stream);
9✔
140
        CurlHelper::setSsl($stream, $this->getConfiguration());
9✔
141
        CurlHelper::setTimeout($stream, $this->getConfiguration());
9✔
142
        CurlHelper::setUserAgent($stream, $this->getConfiguration());
9✔
143
        CurlHelper::setVerbose($stream, $this->getConfiguration(), $requestUrl, $requestBody);
9✔
144

145
        $curlExec    = curl_exec($stream);
9✔
146
        $curlGetInfo = curl_getinfo($stream, CURLINFO_HEADER_SIZE);
9✔
147

148
        $responseHeader = false === is_bool($curlExec) ? $this->parseheader(substr($curlExec, 0, $curlGetInfo)) : [];
9✔
149
        $responseBody   = false === is_bool($curlExec) ? substr($curlExec, $curlGetInfo) : "";
9✔
150
        $responseInfo   = curl_getinfo($stream);
9✔
151

152
        if (true === $this->getConfiguration()->getDebug()) {
9✔
153

154
            $msg = (new DateTime())->format("c") . " [DEBUG] $requestUrl" . PHP_EOL . "HTTP response body ~BEGIN~" . PHP_EOL . print_r($responseBody, true) . PHP_EOL . "~END~" . PHP_EOL;
×
155
            error_log($msg, 3, $this->getConfiguration()->getDebugFile());
×
156
        }
157

158
        $response = $this->prepareResponse($requestBody, $requestHeader, $requestUrl, $responseBody, $responseHeader, $responseInfo);
9✔
159

160
        $curlHttpCode = $responseInfo["http_code"];
9✔
161
        if (200 <= $curlHttpCode && $curlHttpCode <= 299) {
9✔
162
            return $response;
9✔
163
        }
164

165
        $msg = curl_errno($stream);
×
166
        if (0 === $curlHttpCode) {
×
167

168
            $msg = "Call to $requestUrl failed, but for an unknown reason. This could happen if you are disconnected from the network.";
×
169

170
            if (false === empty(curl_error($stream))) {
×
171
                $msg = "Call to $requestUrl failed : " . curl_error($stream);
×
172
            }
173
        }
174

175
        throw new RequestCallException((string) $msg, $curlHttpCode, $response);
×
176
    }
177

178
    /**
179
     * {@inheritDoc}
180
     */
181
    public function clearHeaders(): RequestInterface {
182
        return $this->setHeaders([]);
9✔
183
    }
184

185
    /**
186
     * {@inheritDoc}
187
     */
188
    public function clearPostData(): RequestInterface {
189
        return $this->setPostData([]);
9✔
190
    }
191

192
    /**
193
     * {@inheritDoc}
194
     */
195
    public function clearQueryData(): RequestInterface {
196
        return $this->setQueryData([]);
9✔
197
    }
198

199
    /**
200
     * {@inheritDoc}
201
     */
202
    public function getConfiguration(): Configuration {
203
        return $this->configuration;
72✔
204
    }
205

206
    /**
207
     * {@inheritDoc}
208
     */
209
    public function getHeaders(): array {
210
        return $this->headers;
90✔
211
    }
212

213
    /**
214
     * {@inheritDoc}
215
     */
216
    public function getMethod(): string {
217
        return $this->method;
72✔
218
    }
219

220
    /**
221
     * {@inheritDoc}
222
     */
223
    public function getPostData(): array {
224
        return $this->postData;
99✔
225
    }
226

227
    /**
228
     * {@inheritDoc}
229
     */
230
    public function getQueryData(): array {
231
        return $this->queryData;
90✔
232
    }
233

234
    /**
235
     * {@inheritDoc}
236
     */
237
    public function getResourcePath(): string {
238
        return $this->resourcePath;
72✔
239
    }
240

241
    /**
242
     * Merge the headers.
243
     *
244
     * @return string[] Returns the merged headers.
245
     */
246
    private function mergeHeaders(): array {
247

248
        $headers = [];
9✔
249
        foreach (array_merge($this->getConfiguration()->getHeaders(), $this->getHeaders()) as $key => $value) {
9✔
250
            $headers[] = implode(": ", [$key, $value]);
9✔
251
        }
252

253
        return $headers;
9✔
254
    }
255

256
    /**
257
     * Merge the URL.
258
     *
259
     * @return string Returns the merged URL.
260
     */
261
    private function mergeUrl(): string {
262

263
        $mergedURL = [
7✔
264
            $this->getConfiguration()->getHost(),
9✔
265
        ];
7✔
266

267
        if (null !== $this->getResourcePath() && "" !== $this->getResourcePath()) {
9✔
268
            $mergedURL[] = $this->getResourcePath();
9✔
269
        }
270

271
        return implode("/", $mergedURL);
9✔
272
    }
273

274
    /**
275
     * Parse the raw header.
276
     *
277
     * @param string $rawHeader The raw header.
278
     * @return array<string,string> Returns the headers.
279
     */
280
    private function parseHeader(string $rawHeader): array {
281

282
        $headers = [];
9✔
283
        $key     = "";
9✔
284

285
        foreach (explode("\n", $rawHeader) as $h) {
9✔
286

287
            $h = explode(":", $h, 2);
9✔
288

289
            if (true === isset($h[1])) {
9✔
290

291
                if (false === isset($headers[$h[0]])) {
9✔
292
                    $headers[$h[0]] = trim($h[1]);
9✔
293
                } else if (true === is_array($headers[$h[0]])) {
×
294
                    $headers[$h[0]] = array_merge($headers[$h[0]], [trim($h[1])]);
×
295
                } else {
296
                    $headers[$h[0]] = array_merge([$headers[$h[0]]], [trim($h[1])]);
×
297
                }
298

299
                $key = $h[0];
9✔
300
            } else {
301

302
                if ("\t" === substr($h[0], 0, 1)) {
9✔
303
                    $headers[$key] .= "\r\n\t" . trim($h[0]);
×
304
                } else if (!$key) {
9✔
305
                    $headers[0] = trim($h[0]);
9✔
306
                }
307
            }
308
        }
309

310
        return $headers;
9✔
311
    }
312

313
    /**
314
     * Prepare a response.
315
     *
316
     * @param string $requestBody The request body.
317
     * @param array<string,string> $requestHeader The request header.
318
     * @param string $requestUri The request URI.
319
     * @param string $responseBody The response body.
320
     * @param array<string,string> $responseHeader The response header.
321
     * @param array<string,string> $responseInfo The response info.
322
     * @return ResponseInterface Returns the response.
323
     */
324
    private function prepareResponse(string $requestBody, array $requestHeader, string $requestUri, string $responseBody, array $responseHeader, array $responseInfo): ResponseInterface {
325

326
        /** @var Response $response */
327
        $response = CurlFactory::newCURLResponse();
9✔
328
        $response->setRequestBody($requestBody);
9✔
329
        $response->setRequestHeader($requestHeader);
9✔
330
        $response->setRequestUrl($requestUri);
9✔
331
        $response->setResponseBody($responseBody);
9✔
332
        $response->setResponseHeader($responseHeader);
9✔
333
        $response->setResponseInfo($responseInfo);
9✔
334

335
        return $response;
9✔
336
    }
337

338
    /**
339
     * {@inheritDoc}
340
     */
341
    public function removeHeader(string $name): RequestInterface {
342

343
        if (true === array_key_exists($name, $this->headers)) {
9✔
344
            unset($this->headers[$name]);
9✔
345
        }
346

347
        return $this;
9✔
348
    }
349

350
    /**
351
     * {@inheritDoc}
352
     */
353
    public function removePostData(string $name): RequestInterface {
354

355
        if (true === array_key_exists($name, $this->postData)) {
9✔
356
            unset($this->postData[$name]);
9✔
357
        }
358

359
        return $this;
9✔
360
    }
361

362
    /**
363
     * {@inheritDoc}
364
     */
365
    public function removeQueryData(string $name): RequestInterface {
366

367
        if (true === array_key_exists($name, $this->queryData)) {
9✔
368
            unset($this->queryData[$name]);
9✔
369
        }
370

371
        return $this;
9✔
372
    }
373

374
    /**
375
     * Set the configuration.
376
     *
377
     * @param Configuration $configuration The configuration.
378
     * @return RequestInterface Returns this request.
379
     */
380
    protected function setConfiguration(Configuration $configuration): RequestInterface {
381
        $this->configuration = $configuration;
198✔
382
        return $this;
198✔
383
    }
384

385
    /**
386
     * Set the headers.
387
     *
388
     * @param array<string,string> $headers The headers.
389
     * @return RequestInterface Returns this request.
390
     */
391
    protected function setHeaders(array $headers): RequestInterface {
392
        $this->headers = $headers;
198✔
393
        return $this;
198✔
394
    }
395

396
    /**
397
     * Set the method.
398
     *
399
     * @param string $method The method.
400
     * @return RequestInterface Returns this request.
401
     * @throws InvalidArgumentException Throws an invalid argument exception if the method is invalid.
402
     */
403
    protected function setMethod(string $method): RequestInterface {
404

405
        switch ($method) {
406
            case self::METHOD_DELETE:
198✔
407
            case self::METHOD_GET:
180✔
408
            case self::METHOD_HEAD:
126✔
409
            case self::METHOD_OPTIONS:
108✔
410
            case self::METHOD_PATCH:
90✔
411
            case self::METHOD_POST:
72✔
412
            case self::METHOD_PUT:
18✔
413
                $this->method = $method;
198✔
414
                break;
198✔
415
            default:
416
                throw new InvalidArgumentException(sprintf('The HTTP method "%s" is invalid', $method));
×
417
        }
418

419
        return $this;
198✔
420
    }
421

422
    /**
423
     * Set the POST data.
424
     *
425
     * @param array<string,string> $postData The POST data.
426
     * @return RequestInterface Returns this request.
427
     */
428
    protected function setPostData(array $postData): RequestInterface {
429
        $this->postData = $postData;
198✔
430
        return $this;
198✔
431
    }
432

433
    /**
434
     * Set the query data.
435
     *
436
     * @param array<string,string> $queryData The query data.
437
     * @return RequestInterface Returns this request.
438
     */
439
    protected function setQueryData(array $queryData): RequestInterface {
440
        $this->queryData = $queryData;
198✔
441
        return $this;
198✔
442
    }
443

444
    /**
445
     * {@inheritDoc}
446
     */
447
    public function setResourcePath(?string $resourcePath): RequestInterface {
448

449
        if (null !== $resourcePath) {
198✔
450
            $this->resourcePath = preg_replace("/^\//", "", trim($resourcePath));
135✔
451
        }
452

453
        return $this;
198✔
454
    }
455
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc