Request::getHttpClient()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace seregazhuk\PinterestBot\Api;
4
5
use seregazhuk\PinterestBot\Helpers\FileHelper;
6
use seregazhuk\PinterestBot\Helpers\UrlBuilder;
7
use seregazhuk\PinterestBot\Api\Contracts\HttpClient;
8
use seregazhuk\PinterestBot\Exceptions\InvalidRequest;
9
10
/**
11
 * Class Request.
12
 */
13
class Request
14
{
15
    const DEFAULT_TOKEN = '1234';
16
17
    /**
18
     * @var HttpClient
19
     */
20
    protected $httpClient;
21
22
    /**
23
     * @var bool
24
     */
25
    protected $loggedIn;
26
27
    /**
28
     *
29
     * @var string
30
     */
31
    protected $filePathToUpload;
32
33
    /**
34
     * @var string
35
     */
36
    protected $csrfToken = '';
37
38
    /**
39
     * @var string
40
     */
41
    protected $postFileData;
42
43
    /**
44
     * Common headers needed for every query.
45
     *
46
     * @var array
47
     */
48
    protected $requestHeaders = [
49
        'Accept: application/json, text/javascript, */*; q=0.01',
50
        'Accept-Language: en-US,en;q=0.5',
51
        'DNT: 1',
52
        'X-Pinterest-AppState: active',
53
        'X-NEW-APP: 1',
54
        'X-APP-VERSION: f9d1262',
55
        'X-Pinterest-AppState:active',
56
        'X-Requested-With: XMLHttpRequest',
57
];
58
59
    /**
60
     * @param HttpClient $http
61
     */
62
    public function __construct(HttpClient $http)
63
    {
64
        $this->httpClient = $http;
65
        $this->loggedIn = false;
66
    }
67
68
    /**
69
     * @param string $pathToFile
70
     * @param string $url
71
     * @return string
72
     */
73
    public function upload($pathToFile, $url)
74
    {
75
        $this->filePathToUpload = $pathToFile;
76
77
        return $this->exec($url);
78
    }
79
80
    /**
81
     * Executes request to Pinterest API.
82
     *
83
     * @param string $resourceUrl
84
     * @param string $postString
85
     *
86
     * @return string
87
     */
88
    public function exec($resourceUrl, $postString = '')
89
    {
90
        $url = UrlBuilder::buildApiUrl($resourceUrl);
91
        $headers = $this->getHttpHeaders();
92
        $postString = $this->filePathToUpload ? $this->postFileData : $postString;
93
94
        $result = $this
95
            ->httpClient
96
            ->execute($url, $postString, $headers);
97
98
        $this->setTokenFromCookies();
99
100
        $this->filePathToUpload = null;
101
102
        return $result;
103
    }
104
105
    /**
106
     * @return array
107
     */
108
    protected function getHttpHeaders()
109
    {
110
        $headers = $this->getDefaultHttpHeaders();
111
        if ($this->csrfToken === self::DEFAULT_TOKEN) {
112
            $headers[] = 'Cookie: csrftoken=' . self::DEFAULT_TOKEN . ';';
113
        }
114
115
        return $headers;
116
    }
117
118
    /**
119
     * @return bool
120
     */
121
    public function hasToken()
122
    {
123
        return !empty($this->csrfToken) && $this->csrfToken !== self::DEFAULT_TOKEN;
124
    }
125
    
126
    /**
127
     * Clear token information.
128
     *
129
     * @return $this
130
     */
131
    protected function clearToken()
132
    {
133
        $this->csrfToken = self::DEFAULT_TOKEN;
134
135
        return $this;
136
    }
137
138
    /**
139
     * Load cookies for this username and check if it was logged in.
140
     * @param string $username
141
     * @return bool
142
     */
143
    public function autoLogin($username)
144
    {
145
        $this->loadCookiesFor($username);
146
147
        if (!$this->httpClient->cookie('_auth')) {
148
            return false;
149
        }
150
151
        $this->login();
152
153
        return true;
154
    }
155
156
    /**
157
     * @param string $username
158
     * @return $this
159
     */
160
    public function loadCookiesFor($username)
161
    {
162
        $this->dropCookies();
163
        $this->httpClient->loadCookies($username);
164
165
        return $this;
166
    }
167
168
    /**
169
     * Mark client as logged.
170
     */
171
    public function login()
172
    {
173
        $this->setTokenFromCookies();
174
175
        if (!empty($this->csrfToken)) {
176
            $this->loggedIn = true;
177
        }
178
179
        return $this;
180
    }
181
182
    /**
183
     * Mark client as logged out.
184
     */
185
    public function logout()
186
    {
187
        $this->clearToken();
188
        $this->loggedIn = false;
189
    }
190
191
    /**
192
     * Get current auth status.
193
     *
194
     * @return bool
195
     */
196
    public function isLoggedIn()
197
    {
198
        return $this->loggedIn;
199
    }
200
201
    /**
202
     * Create request string.
203
     *
204
     * @param array $data
205
     * @param array|null $bookmarks
206
     * @return string
207
     */
208
    public function createQuery(array $data = [], array $bookmarks = [])
209
    {
210
        $data = empty($data) ? [] : $data;
211
212
        $request = $this->createRequestData(['options' => $data], $bookmarks);
213
214
        return UrlBuilder::buildRequestString($request);
215
    }
216
217
    /**
218
     * @param array|object $data
219
     * @param array $bookmarks
220
     * @return array
221
     */
222
    public function createRequestData(array $data = [], array $bookmarks = [])
223
    {
224
        if (!empty($bookmarks)) {
225
            $data['options']['bookmarks'] = $bookmarks;
226
        }
227
228
        if (empty($data)) {
229
            $data = ['options' => new \stdClass()];
230
        }
231
232
        $data['context'] = new \stdClass();
233
234
        return [
235
            'source_url' => '',
236
            'data'       => json_encode($data),
237
        ];
238
    }
239
240
    /**
241
     * Trying to execGet csrf token from cookies.
242
     *
243
     * @return $this
244
     */
245
    protected function setTokenFromCookies()
246
    {
247
        if ($token = $this->httpClient->cookie('csrftoken')) {
248
            $this->csrfToken = $token;
249
        }
250
251
        return $this;
252
    }
253
254
    /**
255
     * @return array
256
     */
257
    protected function getDefaultHttpHeaders()
258
    {
259
        return array_merge(
260
            $this->requestHeaders,
261
            $this->getContentTypeHeader(),
262
            [
263
                'Host: ' . UrlBuilder::HOST,
264
                'Origin: ' . UrlBuilder::URL_BASE,
265
                'X-CSRFToken: ' . $this->csrfToken
266
            ]
267
        );
268
    }
269
270
    /**
271
     * If we are uploading file, we should build boundary form data. Otherwise
272
     * it is simple urlencoded form.
273
     *
274
     * @return array
275
     */
276
    protected function getContentTypeHeader()
277
    {
278
        return $this->filePathToUpload ?
279
            $this->makeHeadersForUpload() :
280
            ['Content-Type: application/x-www-form-urlencoded; charset=UTF-8;'];
281
    }
282
283
    /**
284
     * @param string $delimiter
285
     * @return $this
286
     * @throws InvalidRequest
287
     */
288
    protected function buildFilePostData($delimiter)
289
    {
290
        $data = "--$delimiter\r\n";
291
        $data .= 'Content-Disposition: form-data; name="img"; filename="' . basename($this->filePathToUpload) . '"' . "\r\n";
292
        $data .= 'Content-Type: ' . FileHelper::getMimeType($this->filePathToUpload) . "\r\n\r\n";
293
        $data .= file_get_contents($this->filePathToUpload) . "\r\n";
294
        $data .= "--$delimiter--\r\n";
295
296
        $this->postFileData = $data;
297
298
        return $this;
299
    }
300
301
    /**
302
     * @return array
303
     * @throws InvalidRequest
304
     */
305
    protected function makeHeadersForUpload()
306
    {
307
        $delimiter = '-------------' . uniqid();
308
        $this->buildFilePostData($delimiter);
309
310
        return [
311
            'Content-Type: multipart/form-data; boundary=' . $delimiter,
312
            'Content-Length: ' . strlen($this->postFileData)
313
        ];
314
    }
315
316
    /**
317
     * @return HttpClient
318
     */
319
    public function getHttpClient()
320
    {
321
        return $this->httpClient;
322
    }
323
324
    /**
325
     * @return string
326
     */
327
    public function getCurrentUrl()
328
    {
329
        return $this->httpClient->getCurrentUrl();
330
    }
331
332
    /**
333
     * @return $this
334
     */
335
    public function dropCookies()
336
    {
337
        $this->httpClient->removeCookies();
338
        $this->clearToken();
339
340
        return $this;
341
    }
342
}
343