Passed
Push — master ( 473b33...57ebbd )
by Shahrad
01:22
created

Client::setCurlOpts()   C

Complexity

Conditions 10
Paths 192

Size

Total Lines 52
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 27
c 0
b 0
f 0
dl 0
loc 52
rs 6.9
cc 10
nc 192
nop 3

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace EasyHttp;
4
5
use CurlHandle;
6
use EasyHttp\Model\DownloadResult;
7
use EasyHttp\Model\HttpOptions;
8
use EasyHttp\Model\HttpResponse;
9
use EasyHttp\Traits\ClientTrait;
10
11
/**
12
 * Client
13
 *
14
 * @link    https://github.com/shahradelahi/easy-http
15
 * @author  Shahrad Elahi (https://github.com/shahradelahi)
16
 * @license https://github.com/shahradelahi/easy-http/blob/master/LICENSE (MIT License)
17
 */
18
class Client
19
{
20
21
    use ClientTrait;
22
23
    /**
24
     * Set has self-signed certificate
25
     *
26
     * This is used to set the curl option CURLOPT_SSL_VERIFYPEER
27
     * and CURLOPT_SSL_VERIFYHOST to false. This is useful when you are
28
     * in local environment, or you have self-signed certificate.
29
     *
30
     * @param bool $has
31
     * @return void
32
     */
33
    public static function setHasSelfSignedCertificate(bool $has): void
34
    {
35
        define('EZ_CURL_SSL_SELF_SIGNED', $has);
36
    }
37
38
    /**
39
     * This method is used to send a http request to a given url.
40
     *
41
     * @param string $method
42
     * @param string $uri
43
     * @param array|HttpOptions $options
44
     * @return HttpResponse
45
     */
46
    public function request(string $method, string $uri, array|HttpOptions $options = []): HttpResponse
47
    {
48
        $CurlHandle = $this->createCurlHandler($method, $uri, $options);
49
50
        curl_exec($CurlHandle);
51
        curl_close($CurlHandle);
52
53
        return (new HttpResponse())->setResponse([
54
            'status' => curl_getinfo($CurlHandle, CURLINFO_HTTP_CODE),
55
            'body' => curl_exec($CurlHandle),
56
            'info' => curl_getinfo($CurlHandle),
57
            'error' => curl_error($CurlHandle),
58
        ]);
59
    }
60
61
    /**
62
     * Send multiple requests to a given url.
63
     *
64
     * @param array $requests [{method, uri, options}, ...]
65
     * @return array<HttpResponse>
66
     */
67
    public function bulk(array $requests): array
68
    {
69
        $result = [];
70
        $handlers = [];
71
        $multi_handler = curl_multi_init();
72
        foreach ($requests as $request) {
73
74
            $CurlHandle = $this->createCurlHandler(
75
                $request['method'],
76
                $request['uri'],
77
                $request['options'] ?? []
78
            );
79
            $handlers[] = $CurlHandle;
80
            curl_multi_add_handle($multi_handler, $CurlHandle);
0 ignored issues
show
Bug introduced by
It seems like $multi_handler can also be of type true; however, parameter $multi_handle of curl_multi_add_handle() does only seem to accept CurlMultiHandle|resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

80
            curl_multi_add_handle(/** @scrutinizer ignore-type */ $multi_handler, $CurlHandle);
Loading history...
81
82
        }
83
84
        $active = null;
85
        do {
86
            $mrc = curl_multi_exec($multi_handler, $active);
0 ignored issues
show
Bug introduced by
It seems like $multi_handler can also be of type true; however, parameter $multi_handle of curl_multi_exec() does only seem to accept CurlMultiHandle|resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

86
            $mrc = curl_multi_exec(/** @scrutinizer ignore-type */ $multi_handler, $active);
Loading history...
87
        } while ($mrc == CURLM_CALL_MULTI_PERFORM);
88
89
        foreach ($handlers as $handler) {
90
            curl_multi_remove_handle($multi_handler, $handler);
0 ignored issues
show
Bug introduced by
It seems like $multi_handler can also be of type true; however, parameter $multi_handle of curl_multi_remove_handle() does only seem to accept CurlMultiHandle|resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

90
            curl_multi_remove_handle(/** @scrutinizer ignore-type */ $multi_handler, $handler);
Loading history...
91
        }
92
        curl_multi_close($multi_handler);
0 ignored issues
show
Bug introduced by
It seems like $multi_handler can also be of type true; however, parameter $multi_handle of curl_multi_close() does only seem to accept CurlMultiHandle|resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

92
        curl_multi_close(/** @scrutinizer ignore-type */ $multi_handler);
Loading history...
93
94
        foreach ($handlers as $handler) {
95
            $result[] = (new HttpResponse())->setResponse([
96
                'status' => curl_getinfo($handler, CURLINFO_HTTP_CODE),
97
                'body' => curl_exec($handler),
98
                'info' => curl_getinfo($handler),
99
                'error' => curl_error($handler),
100
            ]);
101
        }
102
103
        return $result;
104
    }
105
106
    /**
107
     * Create curl handler.
108
     *
109
     * @param ?string $method
110
     * @param string $uri
111
     * @param array|HttpOptions $options
112
     * @return ?CurlHandle
113
     */
114
    private function createCurlHandler(?string $method, string $uri, array|HttpOptions $options = []): ?CurlHandle
115
    {
116
        $cHandler = curl_init();
117
118
        if (gettype($options) === 'array') {
119
            $options = new HttpOptions(
120
                $this->getOptions($options)
121
            );
122
        }
123
124
        if (count($options->queries) > 0) {
125
            if (!str_contains($uri, '?')) $uri .= '?';
126
            $uri .= $options->getQueryString();
127
        }
128
129
        curl_setopt($cHandler, CURLOPT_URL, $uri);
130
131
        $this->setCurlOpts($cHandler, $method, $options);
0 ignored issues
show
Bug introduced by
It seems like $cHandler can also be of type resource; however, parameter $cHandler of EasyHttp\Client::setCurlOpts() does only seem to accept CurlHandle, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

131
        $this->setCurlOpts(/** @scrutinizer ignore-type */ $cHandler, $method, $options);
Loading history...
132
133
        return $cHandler;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $cHandler could return the type resource which is incompatible with the type-hinted return CurlHandle|null. Consider adding an additional type-check to rule them out.
Loading history...
134
    }
135
136
    /**
137
     * Setup curl options based on the given method and our options.
138
     *
139
     * @param CurlHandle $cHandler
140
     * @param ?string $method
141
     * @param HttpOptions $options
142
     * @return void
143
     */
144
    private function setCurlOpts(CurlHandle $cHandler, ?string $method, HttpOptions $options): void
145
    {
146
        curl_setopt($cHandler, CURLOPT_HEADER, true);
147
        curl_setopt($cHandler, CURLOPT_CUSTOMREQUEST, $method ?? 'GET');
148
149
        # Fetch the header
150
        $fetchedHeaders = [];
151
        foreach ($options->headers as $header => $value) {
152
            $fetchedHeaders[] = $header . ': ' . $value;
153
        }
154
155
        # Set headers
156
        if ($fetchedHeaders != []) {
157
            curl_setopt($cHandler, CURLOPT_HTTPHEADER, $fetchedHeaders);
158
        }
159
160
        # Add body if we have one.
161
        if ($options->body) {
162
            curl_setopt($cHandler, CURLOPT_CUSTOMREQUEST, $method ?? 'POST');
163
            curl_setopt($cHandler, CURLOPT_POSTFIELDS, $options->body);
164
            curl_setopt($cHandler, CURLOPT_POST, true);
165
        }
166
167
        # Check for a proxy
168
        if ($options->proxy != null) {
169
            curl_setopt($cHandler, CURLOPT_PROXY, $options->proxy->getProxy());
170
            curl_setopt($cHandler, CURLOPT_PROXYUSERPWD, $options->proxy->getAuth());
171
            if ($options->proxy->type !== null) {
172
                curl_setopt($cHandler, CURLOPT_PROXYTYPE, $options->proxy->type);
173
                curl_setopt($cHandler, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
174
            }
175
        }
176
177
        curl_setopt($cHandler, CURLOPT_RETURNTRANSFER, true);
178
        curl_setopt($cHandler, CURLOPT_FOLLOWLOCATION, true);
179
180
        # Add and override the custom curl options.
181
        if (count($options->curlOptions) > 0) {
0 ignored issues
show
Bug introduced by
It seems like $options->curlOptions can also be of type null; however, parameter $value of count() does only seem to accept Countable|array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

181
        if (count(/** @scrutinizer ignore-type */ $options->curlOptions) > 0) {
Loading history...
182
            foreach ($options->curlOptions as $option => $value) {
183
                curl_setopt($cHandler, $option, $value);
184
            }
185
        }
186
187
        # if we have a timeout, set it.
188
        if ($options->timeout != null) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $options->timeout of type integer|null against null; this is ambiguous if the integer can be zero. Consider using a strict comparison !== instead.
Loading history...
189
            curl_setopt($cHandler, CURLOPT_TIMEOUT, $options->timeout);
190
        }
191
192
        # If self-signed certs are allowed, set it.
193
        if (EZ_CURL_SSL_SELF_SIGNED === true) {
194
            curl_setopt($cHandler, CURLOPT_SSL_VERIFYPEER, false);
195
            curl_setopt($cHandler, CURLOPT_SSL_VERIFYHOST, false);
196
        }
197
    }
198
199
    /**
200
     * Initialize options from array.
201
     *
202
     * @param array $options
203
     * @return array
204
     */
205
    private function getOptions(array $options): array
206
    {
207
        $defaults = [
208
            'headers' => [],
209
            'body' => null,
210
            'timeout' => null,
211
            'proxy' => null,
212
            'curlOptions' => [],
213
            'queries' => []
214
        ];
215
216
        return array_merge($defaults, $options);
217
    }
218
219
    /**
220
     * Download large files.
221
     *
222
     * This method is used to download large files with
223
     * creating multiple requests.
224
     *
225
     * @param string $url The direct url to the file.
226
     * @param string $path The path to save the file.
227
     * @param array|HttpOptions $options The options to use.
228
     *
229
     * @return DownloadResult
230
     */
231
    public function download(string $url, string $path, array|HttpOptions $options = []): DownloadResult
0 ignored issues
show
Unused Code introduced by
The parameter $url is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

231
    public function download(/** @scrutinizer ignore-unused */ string $url, string $path, array|HttpOptions $options = []): DownloadResult

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $path is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

231
    public function download(string $url, /** @scrutinizer ignore-unused */ string $path, array|HttpOptions $options = []): DownloadResult

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $options is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

231
    public function download(string $url, string $path, /** @scrutinizer ignore-unused */ array|HttpOptions $options = []): DownloadResult

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
232
    {
233
        return new DownloadResult(); // TODO: Implement download() method.
234
    }
235
236
}