Completed
Push — master ( 118874...7ee575 )
by Sergey
07:34 queued 05:25
created

Request::hasToken()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 0
dl 0
loc 4
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: 71842d3',
55
        'X-Requested-With: XMLHttpRequest',
56
        'X-Pinterest-AppState:active',
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
     * @throws InvalidRequest
73
     */
74
    public function upload($pathToFile, $url)
75
    {
76
        $this->filePathToUpload = $pathToFile;
77
78
        return $this->exec($url);
79
    }
80
81
    /**
82
     * Executes request to Pinterest API.
83
     *
84
     * @param string $resourceUrl
85
     * @param string $postString
86
     *
87
     * @return string
88
     */
89
    public function exec($resourceUrl, $postString = '')
90
    {
91
        $url = UrlBuilder::buildApiUrl($resourceUrl);
92
        $headers = $this->getHttpHeaders();
93
        $postString = $this->filePathToUpload ? $this->postFileData : $postString;
94
95
        $result = $this
96
            ->httpClient
97
            ->execute($url, $postString, $headers);
98
99
        $this->setTokenFromCookies();
100
101
        $this->filePathToUpload = null;
102
103
        return $result;
104
    }
105
106
    /**
107
     * @return array
108
     */
109
    protected function getHttpHeaders()
110
    {
111
        $headers = $this->getDefaultHttpHeaders();
112
        if ($this->csrfToken == self::DEFAULT_TOKEN) {
113
            $headers[] = 'Cookie: csrftoken=' . self::DEFAULT_TOKEN . ';';
114
        }
115
116
        return $headers;
117
    }
118
119
    /**
120
     * @return bool
121
     */
122
    public function hasToken()
123
    {
124
        return !empty($this->csrfToken) && $this->csrfToken != self::DEFAULT_TOKEN;
125
    }
126
    
127
    /**
128
     * Clear token information.
129
     *
130
     * @return $this
131
     */
132
    protected function clearToken()
133
    {
134
        $this->csrfToken = self::DEFAULT_TOKEN;
135
136
        return $this;
137
    }
138
139
    /**
140
     * Load cookies for this username and check if it was logged in.
141
     * @param string $username
142
     * @return bool
143
     */
144
    public function autoLogin($username)
145
    {
146
        $this->loadCookiesFor($username);
147
148
        if (!$this->httpClient->cookie('_auth')) {
149
            return false;
150
        }
151
152
        $this->login();
153
154
        return true;
155
    }
156
157
    /**
158
     * @param string $username
159
     * @return $this
160
     */
161
    public function loadCookiesFor($username)
162
    {
163
        $this->dropCookies();
164
        $this->httpClient->loadCookies($username);
165
166
        return $this;
167
    }
168
169
    /**
170
     * Mark client as logged.
171
     */
172
    public function login()
173
    {
174
        $this->setTokenFromCookies();
175
176
        if(!empty($this->csrfToken)) {
177
            $this->loggedIn = true;
178
        }
179
180
        return $this;
181
    }
182
183
    /**
184
     * Mark client as logged out.
185
     */
186
    public function logout()
187
    {
188
        $this->clearToken();
189
        $this->loggedIn = false;
190
    }
191
192
    /**
193
     * Get current auth status.
194
     *
195
     * @return bool
196
     */
197
    public function isLoggedIn()
198
    {
199
        return $this->loggedIn;
200
    }
201
202
    /**
203
     * Create request string.
204
     *
205
     * @param array $data
206
     * @param array|null $bookmarks
207
     * @return string
208
     */
209
    public static function createQuery(array $data = [], $bookmarks = null)
210
    {
211
        $data = empty($data) ? [] : $data;
212
213
        $bookmarks = is_array($bookmarks) ? $bookmarks : [];
214
215
        $request = self::createRequestData(
216
            ['options' => $data], $bookmarks
217
        );
218
219
        return UrlBuilder::buildRequestString($request);
220
    }
221
222
    /**
223
     * @param array|object $data
224
     * @param array $bookmarks
225
     * @return array
226
     */
227
    public static function createRequestData(array $data = [], $bookmarks = [])
228
    {
229
        $data = self::prepareArrayToJson($data);
230
231
        if (!empty($bookmarks)) {
232
            $data['options']['bookmarks'] = $bookmarks;
233
        }
234
235
        if (empty($data)) {
236
            $data = ['options' => new \stdClass()];
237
        }
238
239
        $data['context'] = new \stdClass();
240
241
        return [
242
            'source_url' => '',
243
            'data'       => json_encode($data),
244
        ];
245
    }
246
247
    /**
248
     * Cast all non-array values to strings
249
     *
250
     * @param $array
251
     * @return array
252
     */
253
    protected static function prepareArrayToJson(array $array)
254
    {
255
        $result = [];
256
        foreach ($array as $key => $value) {
257
            $result[$key] = is_array($value) ?
258
                self::prepareArrayToJson($value) :
259
                strval($value);
260
        }
261
262
        return $result;
263
    }
264
265
    /**
266
     * Trying to execGet csrf token from cookies.
267
     *
268
     * @return $this
269
     */
270
    protected function setTokenFromCookies()
271
    {
272
        if($token = $this->httpClient->cookie('csrftoken')) {
273
            $this->csrfToken = $token;
274
        }
275
276
        return $this;
277
    }
278
279
    /**
280
     * @return array
281
     */
282
    protected function getDefaultHttpHeaders()
283
    {
284
        return array_merge(
285
            $this->requestHeaders,
286
            $this->getContentTypeHeader(),
287
            [
288
                'Host: ' . UrlBuilder::HOST,
289
                'Origin: ' . UrlBuilder::URL_BASE,
290
                'X-CSRFToken: ' . $this->csrfToken
291
            ]
292
        );
293
    }
294
295
    /**
296
     * If we are uploading file, we should build boundary form data. Otherwise
297
     * it is simple urlencoded form.
298
     *
299
     * @return array
300
     */
301
    protected function getContentTypeHeader()
302
    {
303
        return $this->filePathToUpload ?
304
            $this->makeHeadersForUpload() :
305
            ['Content-Type: application/x-www-form-urlencoded; charset=UTF-8;'];
306
    }
307
308
    /**
309
     * @param string $delimiter
310
     * @return $this
311
     */
312
    protected function buildFilePostData($delimiter)
313
    {
314
        $data = "--$delimiter\r\n";
315
        $data .= 'Content-Disposition: form-data; name="img"; filename="' . basename($this->filePathToUpload) . '"' . "\r\n";
316
        $data .= 'Content-Type: ' . FileHelper::getMimeType($this->filePathToUpload) . "\r\n\r\n";
317
        $data .= file_get_contents($this->filePathToUpload) . "\r\n";
318
        $data .= "--$delimiter--\r\n";
319
320
        $this->postFileData = $data;
321
322
        return $this;
323
    }
324
325
    /**
326
     * @return array
327
     */
328
    protected function makeHeadersForUpload()
329
    {
330
        $delimiter = '-------------' . uniqid();
331
        $this->buildFilePostData($delimiter);
332
333
        return [
334
            'Content-Type: multipart/form-data; boundary=' . $delimiter,
335
            'Content-Length: ' . strlen($this->postFileData)
336
        ];
337
    }
338
339
    /**
340
     * @return HttpClient
341
     */
342
    public function getHttpClient()
343
    {
344
        return $this->httpClient;
345
    }
346
347
    /**
348
     * @return string
349
     */
350
    public function getCurrentUrl()
351
    {
352
        return $this->httpClient->getCurrentUrl();
353
    }
354
355
    /**
356
     * @return $this
357
     */
358
    public function dropCookies()
359
    {
360
        $this->httpClient->removeCookies();
361
        $this->clearToken();
362
363
        return $this;
364
    }
365
}
366