CurlHttpClient::dontUseProxy()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 0
dl 0
loc 10
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace seregazhuk\PinterestBot\Api;
4
5
use seregazhuk\PinterestBot\Helpers\Cookies;
6
use seregazhuk\PinterestBot\Helpers\UrlBuilder;
7
use seregazhuk\PinterestBot\Api\Contracts\HttpClient;
8
9
/**
10
 * Class CurlHttpClient.
11
 */
12
class CurlHttpClient implements HttpClient
13
{
14
    /**
15
     * Custom CURL options for requests.
16
     *
17
     * @var array
18
     */
19
    protected $options = [
20
        CURLOPT_USERAGENT => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36'
21
    ];
22
23
    /**
24
     * @var array
25
     */
26
    protected $headers = [];
27
28
    /**
29
     * Contains the curl instance.
30
     *
31
     * @var resource
32
     */
33
    protected $curl;
34
35
    /**
36
     * Path to cookies file
37
     * @var string
38
     */
39
    protected $cookieJar;
40
41
    /**
42
     * Cookies container
43
     *
44
     * @var Cookies
45
     */
46
    protected $cookies;
47
48
    /**
49
     * @var string
50
     */
51
    protected $currentUrl;
52
53
    /**
54
     * Path to directory to store cookie file
55
     * @var string
56
     */
57
    protected $cookiesPath;
58
59
    public function __construct(Cookies $cookies)
60
    {
61
        $this->cookies = $cookies;
62
    }
63
64
    /**
65
     * Load cookies for a specified username. If a username is empty
66
     * we use a common file for all the anonymous requests.
67
     *
68
     * @param string $username
69
     * @return HttpClient
70
     */
71
    public function loadCookies($username = '')
72
    {
73
        return $this
74
            ->initCookieJar($username)
75
            ->fillCookies();
76
    }
77
78
    /**
79
     * Executes curl request.
80
     *
81
     * @param string $url
82
     * @param string $postString
83
     * @param array $headers
84
     * @return string
85
     */
86
    public function execute($url, $postString = '', array $headers = [])
87
    {
88
        return $this
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->init($url,..., $headers)->callCurl() also could return the type boolean which is incompatible with the documented return type string.
Loading history...
89
            ->init($url, $postString, $headers)
90
            ->callCurl();
91
    }
92
93
    /**
94
     * @return mixed
95
     */
96
    protected function callCurl()
97
    {
98
        $result = curl_exec($this->curl);
99
100
        $this->currentUrl = curl_getinfo($this->curl, CURLINFO_EFFECTIVE_URL);
101
102
        curl_close($this->curl);
103
104
        $this->fillCookies();
105
106
        return $result;
107
    }
108
109
    /**
110
     * Initializes curl resource with options.
111
     *
112
     * @param string $url
113
     * @param string $postString
114
     * @param array $headers
115
     * @return $this
116
     */
117
    protected function init($url, $postString, $headers)
118
    {
119
        $this->headers = $headers;
120
121
        $this->curl = curl_init($url);
0 ignored issues
show
Documentation Bug introduced by
It seems like curl_init($url) can also be of type false. However, the property $curl is declared as type resource. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
122
123
        if (empty($this->cookieJar)) {
124
            $this->loadCookies();
125
        }
126
127
        curl_setopt_array($this->curl, $this->makeHttpOptions($postString));
0 ignored issues
show
Bug introduced by
It seems like $this->curl can also be of type false; however, parameter $ch of curl_setopt_array() does only seem to accept 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

127
        curl_setopt_array(/** @scrutinizer ignore-type */ $this->curl, $this->makeHttpOptions($postString));
Loading history...
128
129
        return $this;
130
    }
131
132
    /**
133
     * @return array
134
     */
135
    protected function getDefaultHttpOptions()
136
    {
137
        return [
138
            CURLOPT_REFERER        => UrlBuilder::URL_BASE,
139
            CURLOPT_ENCODING       => 'gzip,deflate,br',
140
            CURLOPT_FRESH_CONNECT  => true,
141
            CURLOPT_HTTPHEADER     => $this->headers,
142
            CURLOPT_COOKIEFILE     => $this->cookieJar,
143
            CURLOPT_COOKIEJAR      => $this->cookieJar,
144
            CURLOPT_RETURNTRANSFER => true,
145
            CURLOPT_SSL_VERIFYPEER => false,
146
            CURLOPT_FOLLOWLOCATION => true,
147
        ];
148
    }
149
150
    /**
151
     * Adds necessary curl options for query.
152
     *
153
     * @param string $postString POST query string
154
     *
155
     * @return array
156
     */
157
    protected function makeHttpOptions($postString = '')
158
    {
159
        // Union custom Curl options and default ones.
160
        $options = array_replace(
161
            $this->options,
162
            $this->getDefaultHttpOptions()
163
        );
164
165
        if (!empty($postString)) {
166
            $options[CURLOPT_POST] = true;
167
            $options[CURLOPT_POSTFIELDS] = $postString;
168
        }
169
170
        return $options;
171
    }
172
173
    /**
174
     * Set custom Curl options to override default
175
     *
176
     * @codeCoverageIgnore
177
     * @param array $options
178
     * @return HttpClient
179
     */
180
    public function setOptions(array $options)
181
    {
182
        $this->options = $options;
183
184
        return $this;
185
    }
186
187
    /**
188
     * Get a cookie value by name
189
     *
190
     * @param $name
191
     * @return mixed
192
     */
193
    public function cookie($name)
194
    {
195
        return $this->cookies->get($name);
196
    }
197
198
    /**
199
     * Get all cookies
200
     *
201
     * @return array
202
     */
203
    public function cookies()
204
    {
205
        return $this->cookies->all();
206
    }
207
208
    /**
209
     * Set directory to store all cookie files.
210
     *
211
     * @codeCoverageIgnore
212
     * @param string $path
213
     * @return $this
214
     */
215
    public function setCookiesPath($path)
216
    {
217
        $this->cookiesPath = $path;
218
219
        return $this;
220
    }
221
222
    /**
223
     * @return $this
224
     */
225
    public function removeCookies()
226
    {
227
        if (file_exists($this->cookieJar)) {
228
            unlink($this->cookieJar);
229
        }
230
231
        $this->cookieJar = null;
232
233
        return $this;
234
    }
235
236
    /**
237
     * @param $username
238
     * @return $this
239
     */
240
    protected function initCookieJar($username)
241
    {
242
        $this->cookieJar = $this->initCookieFile($username);
243
244
        return $this;
245
    }
246
247
    /**
248
     * Returns cookie file name according to the provided username.
249
     *
250
     * @param string $username
251
     * @return string
252
     */
253
    protected function initCookieFile($username)
254
    {
255
        $cookieName = self::COOKIE_PREFIX . $username;
256
        $cookieFilePath = $this->getCookiesPath() . DIRECTORY_SEPARATOR . $cookieName;
257
258
        if (!file_exists($cookieFilePath)) {
259
            touch($cookieFilePath);
260
        }
261
262
        return $cookieFilePath;
263
    }
264
265
    /**
266
     * @return string
267
     */
268
    public function getCookiesPath()
269
    {
270
        return $this->cookiesPath ? : sys_get_temp_dir();
271
    }
272
273
    /**
274
     * @return $this
275
     */
276
    protected function fillCookies()
277
    {
278
        if (!empty($this->cookieJar)) {
279
            $this->cookies->fill($this->cookieJar);
280
        }
281
282
        return $this;
283
    }
284
285
    /**
286
     * @codeCoverageIgnore
287
     * @return string
288
     */
289
    public function getCurrentUrl()
290
    {
291
        return $this->currentUrl;
292
    }
293
294
    /**
295
     * @param string $host '192.168.1.1'
296
     * @param string $port '12345'
297
     * @param string $auth Authentication string: 'username:password'
298
     * @param string $type HTTP|SOCKS
299
     * @return HttpClient
300
     */
301
    public function useProxy($host, $port, $auth = null, $type = null)
302
    {
303
        $proxy = [
304
            CURLOPT_PROXY     => $host,
305
            CURLOPT_PROXYPORT => $port,
306
            CURLOPT_PROXYTYPE => $type ?: CURLPROXY_HTTP,
307
        ];
308
309
        if (null !== $auth) {
310
            $proxy[CURLOPT_PROXYUSERPWD] = $auth;
311
        }
312
313
        return $this->setOptions($proxy);
314
    }
315
316
    public function dontUseProxy()
317
    {
318
        unset(
319
            $this->options[CURLOPT_PROXY],
320
            $this->options[CURLOPT_PROXYPORT],
321
            $this->options[CURLOPT_PROXYTYPE],
322
            $this->options[CURLOPT_PROXYUSERPWD]
323
        );
324
325
        return $this;
326
    }
327
328
    /**
329
     * @return bool
330
     */
331
    public function usesProxy()
332
    {
333
        return isset($this->options[CURLOPT_PROXY]);
334
    }
335
336
    /**
337
     * @codeCoverageIgnore
338
     * @param string $host
339
     * @param string $port
340
     * @param null $auth
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $auth is correct as it would always require null to be passed?
Loading history...
341
     * @return HttpClient
342
     */
343
    public function useSocksProxy($host, $port, $auth = null)
344
    {
345
        return $this->useProxy($host, $port, CURLPROXY_SOCKS5, $auth);
346
    }
347
}
348