Completed
Pull Request — master (#308)
by Sergey
06:18
created

Request::prepareArrayToJson()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 3
nop 1
dl 0
loc 11
rs 9.4285
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-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
     * @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
        if (!empty($bookmarks)) {
230
            $data['options']['bookmarks'] = $bookmarks;
231
        }
232
233
        if (empty($data)) {
234
            $data = ['options' => new \stdClass()];
235
        }
236
237
        $data['context'] = new \stdClass();
238
239
        return [
240
            'source_url' => '',
241
            'data'       => json_encode($data),
242
        ];
243
    }
244
245
    /**
246
     * Trying to execGet csrf token from cookies.
247
     *
248
     * @return $this
249
     */
250
    protected function setTokenFromCookies()
251
    {
252
        if($token = $this->httpClient->cookie('csrftoken')) {
253
            $this->csrfToken = $token;
254
        }
255
256
        return $this;
257
    }
258
259
    /**
260
     * @return array
261
     */
262
    protected function getDefaultHttpHeaders()
263
    {
264
        return array_merge(
265
            $this->requestHeaders,
266
            $this->getContentTypeHeader(),
267
            [
268
                'Host: ' . UrlBuilder::HOST,
269
                'Origin: ' . UrlBuilder::URL_BASE,
270
                'X-CSRFToken: ' . $this->csrfToken
271
            ]
272
        );
273
    }
274
275
    /**
276
     * If we are uploading file, we should build boundary form data. Otherwise
277
     * it is simple urlencoded form.
278
     *
279
     * @return array
280
     */
281
    protected function getContentTypeHeader()
282
    {
283
        return $this->filePathToUpload ?
284
            $this->makeHeadersForUpload() :
285
            ['Content-Type: application/x-www-form-urlencoded; charset=UTF-8;'];
286
    }
287
288
    /**
289
     * @param string $delimiter
290
     * @return $this
291
     */
292
    protected function buildFilePostData($delimiter)
293
    {
294
        $data = "--$delimiter\r\n";
295
        $data .= 'Content-Disposition: form-data; name="img"; filename="' . basename($this->filePathToUpload) . '"' . "\r\n";
296
        $data .= 'Content-Type: ' . FileHelper::getMimeType($this->filePathToUpload) . "\r\n\r\n";
297
        $data .= file_get_contents($this->filePathToUpload) . "\r\n";
298
        $data .= "--$delimiter--\r\n";
299
300
        $this->postFileData = $data;
301
302
        return $this;
303
    }
304
305
    /**
306
     * @return array
307
     */
308
    protected function makeHeadersForUpload()
309
    {
310
        $delimiter = '-------------' . uniqid();
311
        $this->buildFilePostData($delimiter);
312
313
        return [
314
            'Content-Type: multipart/form-data; boundary=' . $delimiter,
315
            'Content-Length: ' . strlen($this->postFileData)
316
        ];
317
    }
318
319
    /**
320
     * @return HttpClient
321
     */
322
    public function getHttpClient()
323
    {
324
        return $this->httpClient;
325
    }
326
327
    /**
328
     * @return string
329
     */
330
    public function getCurrentUrl()
331
    {
332
        return $this->httpClient->getCurrentUrl();
333
    }
334
335
    /**
336
     * @return $this
337
     */
338
    public function dropCookies()
339
    {
340
        $this->httpClient->removeCookies();
341
        $this->clearToken();
342
343
        return $this;
344
    }
345
}
346