Completed
Pull Request — master (#572)
by Frédéric
01:32
created

CurlClient   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 132
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 20
lcom 1
cbo 3
dl 0
loc 132
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A setCurlParameters() 0 4 1
A setForceSSL3() 0 6 1
F retrieveResponse() 0 78 18
1
<?php
2
3
namespace OAuth\Common\Http\Client;
4
5
use InvalidArgumentException;
6
use OAuth\Common\Http\Exception\TokenResponseException;
7
use OAuth\Common\Http\Uri\UriInterface;
8
9
/**
10
 * Client implementation for cURL.
11
 */
12
class CurlClient extends AbstractClient
13
{
14
    /**
15
     * If true, explicitly sets cURL to use SSL version 3. Use this if cURL
16
     * compiles with GnuTLS SSL.
17
     *
18
     * @var bool
19
     */
20
    private $forceSSL3 = false;
21
22
    /**
23
     * Additional parameters (as `key => value` pairs) to be passed to `curl_setopt`.
24
     *
25
     * @var array
26
     */
27
    private $parameters = [];
28
29
    /**
30
     * Additional `curl_setopt` parameters.
31
     *
32
     * @param array $parameters
33
     */
34
    public function setCurlParameters(array $parameters): void
35
    {
36
        $this->parameters = $parameters;
37
    }
38
39
    /**
40
     * @param bool $force
41
     *
42
     * @return CurlClient
43
     */
44
    public function setForceSSL3($force)
45
    {
46
        $this->forceSSL3 = $force;
47
48
        return $this;
49
    }
50
51
    /**
52
     * Any implementing HTTP providers should send a request to the provided endpoint with the parameters.
53
     * They should return, in string form, the response body and throw an exception on error.
54
     *
55
     * @param UriInterface $endpoint
56
     * @param mixed        $requestBody
57
     * @param array        $extraHeaders
58
     * @param string       $method
59
     *
60
     * @return string
61
     *
62
     * @throws TokenResponseException
63
     * @throws \InvalidArgumentException
64
     */
65
    public function retrieveResponse(
66
        UriInterface $endpoint,
67
        $requestBody,
68
        array $extraHeaders = [],
69
        $method = 'POST'
70
    ) {
71
        // Normalize method name
72
        $method = strtoupper($method);
73
74
        $this->normalizeHeaders($extraHeaders);
75
76
        if ($method === 'GET' && !empty($requestBody)) {
77
            throw new InvalidArgumentException('No body expected for "GET" request.');
78
        }
79
80
        if (!isset($extraHeaders['Content-Type']) && $method === 'POST' && is_array($requestBody)) {
81
            $extraHeaders['Content-Type'] = 'Content-Type: application/x-www-form-urlencoded';
82
        }
83
84
        $extraHeaders['Host'] = 'Host: ' . $endpoint->getHost();
85
        $extraHeaders['Connection'] = 'Connection: close';
86
87
        $ch = curl_init();
88
89
        curl_setopt($ch, CURLOPT_URL, $endpoint->getAbsoluteUri());
90
91
        if ($method === 'POST' || $method === 'PUT' || $method === 'PATCH') {
92
            if ($requestBody && is_array($requestBody)) {
93
                $requestBody = http_build_query($requestBody, '', '&');
94
            }
95
96
            if ($method === 'PUT' || $method === 'PATCH') {
97
                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
98
            } else {
99
                curl_setopt($ch, CURLOPT_POST, true);
100
            }
101
102
            curl_setopt($ch, CURLOPT_POSTFIELDS, $requestBody);
103
        } else {
104
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
105
        }
106
107
        if ($this->maxRedirects > 0) {
108
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
109
            curl_setopt($ch, CURLOPT_MAXREDIRS, $this->maxRedirects);
110
        }
111
112
        curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
113
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
114
        curl_setopt($ch, CURLOPT_HEADER, false);
115
        curl_setopt($ch, CURLOPT_HTTPHEADER, $extraHeaders);
116
        curl_setopt($ch, CURLOPT_USERAGENT, $this->userAgent);
117
118
        foreach ($this->parameters as $key => $value) {
119
            curl_setopt($ch, $key, $value);
120
        }
121
122
        if ($this->forceSSL3) {
123
            curl_setopt($ch, CURLOPT_SSLVERSION, 3);
124
        }
125
126
        $response = curl_exec($ch);
127
        $responseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
128
129
        if (false === $response) {
130
            $errNo = curl_errno($ch);
131
            $errStr = curl_error($ch);
132
            curl_close($ch);
133
            if (empty($errStr)) {
134
                throw new TokenResponseException('Failed to request resource.', $responseCode);
135
            }
136
            throw new TokenResponseException('cURL Error # ' . $errNo . ': ' . $errStr, $responseCode);
137
        }
138
139
        curl_close($ch);
140
141
        return $response;
142
    }
143
}
144