Completed
Pull Request — master (#229)
by Sergey
02:32
created

CurlHttpClient::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
rs 10
cc 1
eloc 2
nc 1
nop 1
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 CurlAdapter.
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 specified username
66
     *
67
     * @param string $username
68
     * @return HttpClient
69
     */
70
    public function loadCookies($username = '')
71
    {
72
        return $this->initCookieJar($username)
73
            ->fillCookies();
74
    }
75
76
    /**
77
     * Executes curl request.
78
     *
79
     * @param string $url
80
     * @param string $postString
81
     * @param array $headers
82
     * @return string
83
     */
84
    public function execute($url, $postString = '', array $headers = [])
85
    {
86
        return $this
87
            ->init($url, $postString, $headers)
88
            ->callCurl();
89
    }
90
91
    /**
92
     * @return mixed
93
     */
94
    protected function callCurl()
95
    {
96
        $res = curl_exec($this->curl);
97
98
        $this->currentUrl = curl_getinfo($this->curl, CURLINFO_EFFECTIVE_URL);
99
100
        curl_close($this->curl);
101
102
        $this->fillCookies();
103
104
        return $res;
105
    }
106
107
    /**
108
     * Initializes curl resource with options.
109
     *
110
     * @param string $url
111
     * @param string $postString
112
     * @param array $headers
113
     * @return $this
114
     */
115
    protected function init($url, $postString, $headers)
116
    {
117
        $this->headers = $headers;
118
119
        $this->curl = curl_init($url);
120
121
        if (empty($this->cookieJar)) {
122
            $this->loadCookies();
123
        }
124
125
        curl_setopt_array($this->curl, $this->makeHttpOptions($postString));
126
127
        return $this;
128
    }
129
130
    /**
131
     * @return array
132
     */
133
    protected function getDefaultHttpOptions()
134
    {
135
        return [
136
            CURLOPT_REFERER        => UrlBuilder::URL_BASE,
137
            CURLOPT_ENCODING       => 'gzip,deflate, br',
138
            CURLOPT_FRESH_CONNECT => true,
139
            CURLOPT_COOKIEJAR      => $this->cookieJar,
140
            CURLOPT_HTTPHEADER     => $this->headers,
141
            CURLOPT_COOKIEFILE     => $this->cookieJar,
142
            CURLOPT_RETURNTRANSFER => true,
143
            CURLOPT_SSL_VERIFYPEER => false,
144
            CURLOPT_FOLLOWLOCATION => true,
145
        ];
146
    }
147
148
    /**
149
     * Adds necessary curl options for query.
150
     *
151
     * @param string $postString POST query string
152
     *
153
     * @return array
154
     */
155
    protected function makeHttpOptions($postString = '')
156
    {
157
        // Union custom Curl options and default.
158
        $options = array_replace(
159
            $this->options,
160
            $this->getDefaultHttpOptions()
161
        );
162
163
        if (!empty($postString)) {
164
            $options[CURLOPT_POST] = true;
165
            $options[CURLOPT_POSTFIELDS] = $postString;
166
        }
167
168
        return $options;
169
    }
170
171
    /**
172
     * Set custom Curl options to override default
173
     *
174
     * @codeCoverageIgnore
175
     * @param array $options
176
     * @return HttpClient
177
     */
178
    public function setOptions(array $options)
179
    {
180
        $this->options = $options;
181
182
        return $this;
183
    }
184
185
    /**
186
     * Get a cookie value by name
187
     *
188
     * @param $name
189
     * @return mixed
190
     */
191
    public function cookie($name)
192
    {
193
        return $this->cookies->get($name);
194
    }
195
196
    /**
197
     * Get all cookies
198
     *
199
     * @return array
200
     */
201
    public function cookies()
202
    {
203
        return $this->cookies->all();
204
    }
205
206
    /**
207
     * Set directory to store all cookie files.
208
     *
209
     * @codeCoverageIgnore
210
     * @param string $path
211
     * @return $this
212
     */
213
    public function setCookiesPath($path)
214
    {
215
        $this->cookiesPath = $path;
216
217
        return $this;
218
    }
219
220
    /**
221
     * @return $this
222
     */
223
    public function removeCookies()
224
    {
225
        if (file_exists($this->cookieJar)) {
226
            unlink($this->cookieJar);
227
        }
228
229
        return $this;
230
    }
231
232
    /**
233
     * Init cookie file for a specified username. If username is empty we use
234
     * common cookie file for all sessions. If file does not exist it will
235
     * be created in system temp directory.
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 by username. If username is empty we use a
249
     * random cookie name, to be sure we have different cookies
250
     * in parallel sessions.
251
     *
252
     * @param string $username
253
     * @return string
254
     */
255
    protected function initCookieFile($username)
256
    {
257
        if(empty($username)) {
258
            return tempnam($this->getCookiesPath(), self::COOKIE_PREFIX);
259
        }
260
261
        $cookieName = self::COOKIE_PREFIX . $username;
262
        $cookieFilePath = $this->getCookiesPath() . DIRECTORY_SEPARATOR . $cookieName;
263
264
        if (!file_exists($cookieFilePath)) {
265
            touch($cookieFilePath);
266
        }
267
268
        return $cookieFilePath;
269
    }
270
271
    /**
272
     * @return string
273
     */
274
    public function getCookiesPath()
275
    {
276
        return $this->cookiesPath ? : sys_get_temp_dir();
277
    }
278
279
    /**
280
     * @return $this
281
     */
282
    protected function fillCookies()
283
    {
284
        $this->cookies->fill($this->cookieJar);
285
286
        return $this;
287
    }
288
289
    /**
290
     * @codeCoverageIgnore
291
     * @return string
292
     */
293
    public function getCurrentUrl()
294
    {
295
        return $this->currentUrl;
296
    }
297
298
    /**
299
     * @param string $host '192.168.1.1'
300
     * @param string $port '12345'
301
     * @param string $auth Authentication string: 'username:password'
302
     * @param string $type HTTP|SOCKS
303
     * @return HttpClient
304
     */
305
    public function useProxy($host, $port, $auth = null, $type = null)
306
    {
307
        $proxy = [
308
            CURLOPT_PROXY     => $host,
309
            CURLOPT_PROXYPORT => $port,
310
            CURLOPT_PROXYTYPE => $type ? $type : CURLPROXY_HTTP,
311
        ];
312
313
        if($auth) $proxy[CURLOPT_PROXYUSERPWD] = $auth;
0 ignored issues
show
Bug Best Practice introduced by
The expression $auth of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
314
315
        return $this->setOptions($proxy);
316
    }
317
318
    /**
319
     * @codeCoverageIgnore
320
     * @param string $host
321
     * @param string $port
322
     * @param null $auth
323
     * @return HttpClient
324
     */
325
    public function useSocksProxy($host, $port, $auth = null)
326
    {
327
        return $this->useProxy($host, $port, CURLPROXY_SOCKS5, $auth);
328
    }
329
330
    /**
331
     * @param bool $debug
332
     * @return HttpClient
333
     */
334
    public function setDebug($debug)
335
    {
336
        $this->debug = $debug;
0 ignored issues
show
Bug introduced by
The property debug does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
337
338
        return $this;
339
    }
340
}