Completed
Pull Request — master (#237)
by Sergey
02:43
created

Request::getCurrentUrl()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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