Passed
Push — master ( 19517c...d5d6b0 )
by Sergey
01:00
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: 831c928',
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
    /**
121
     * Clear token information.
122
     *
123
     * @return $this
124
     */
125
    protected function clearToken()
126
    {
127
        $this->csrfToken = self::DEFAULT_TOKEN;
128
129
        return $this;
130
    }
131
132
    /**
133
     * Load cookies for this username and check if it was logged in.
134
     * @param string $username
135
     * @return bool
136
     */
137
    public function autoLogin($username)
138
    {
139
        $this->httpClient->loadCookies($username);
140
141
        if (!$this->httpClient->cookie('_auth')) {
142
            return false;
143
        }
144
145
        $this->login();
146
147
        return true;
148
    }
149
150
    /**
151
     * Mark client as logged.
152
     */
153
    public function login()
154
    {
155
        $this->setTokenFromCookies();
156
157
        if(!empty($this->csrfToken)) {
158
            $this->loggedIn = true;
159
        }
160
161
        return $this;
162
    }
163
164
    /**
165
     * Mark client as logged out.
166
     */
167
    public function logout()
168
    {
169
        $this->clearToken();
170
        $this->loggedIn = false;
171
    }
172
173
    /**
174
     * Get current auth status.
175
     *
176
     * @return bool
177
     */
178
    public function isLoggedIn()
179
    {
180
        return $this->loggedIn;
181
    }
182
183
    /**
184
     * Create request string.
185
     *
186
     * @param array $data
187
     * @param array|null $bookmarks
188
     * @return string
189
     */
190
    public static function createQuery(array $data = [], $bookmarks = null)
191
    {
192
        $data = empty($data) ? [] : $data;
193
194
        $bookmarks = is_array($bookmarks) ? $bookmarks : [];
195
196
        $request = self::createRequestData(
197
            ['options' => $data], $bookmarks
198
        );
199
200
        return UrlBuilder::buildRequestString($request);
201
    }
202
203
    /**
204
     * @param array|object $data
205
     * @param array $bookmarks
206
     * @return array
207
     */
208
    public static function createRequestData(array $data = [], $bookmarks = [])
209
    {
210
        $data = self::prepareArrayToJson($data);
211
212
        if (!empty($bookmarks)) {
213
            $data['options']['bookmarks'] = $bookmarks;
214
        }
215
216
        if (empty($data)) {
217
            $data = ['options' => new \stdClass()];
218
        }
219
220
        $data['context'] = new \stdClass();
221
222
        return [
223
            'source_url' => '',
224
            'data'       => json_encode($data),
225
        ];
226
    }
227
228
    /**
229
     * Cast all non-array values to strings
230
     *
231
     * @param $array
232
     * @return array
233
     */
234
    protected static function prepareArrayToJson(array $array)
235
    {
236
        $result = [];
237
        foreach ($array as $key => $value) {
238
            $result[$key] = is_array($value) ?
239
                self::prepareArrayToJson($value) :
240
                strval($value);
241
        }
242
243
        return $result;
244
    }
245
246
    /**
247
     * Trying to execGet csrf token from cookies.
248
     *
249
     * @return $this
250
     */
251
    protected function setTokenFromCookies()
252
    {
253
        if($token = $this->httpClient->cookie('csrftoken')) {
254
            $this->csrfToken = $token;
255
        }
256
257
        return $this;
258
    }
259
260
    /**
261
     * @return array
262
     */
263
    protected function getDefaultHttpHeaders()
264
    {
265
        return array_merge(
266
            $this->requestHeaders,
267
            $this->getContentTypeHeader(),
268
            [
269
                'Host: ' . UrlBuilder::HOST,
270
                'Origin: ' . UrlBuilder::URL_BASE,
271
                'X-CSRFToken: ' . $this->csrfToken
272
            ]
273
        );
274
    }
275
276
    /**
277
     * If we are uploading file, we should build boundary form data. Otherwise
278
     * it is simple urlencoded form.
279
     *
280
     * @return array
281
     */
282
    protected function getContentTypeHeader()
283
    {
284
        return $this->filePathToUpload ?
285
            $this->makeHeadersForUpload() :
286
            ['Content-Type: application/x-www-form-urlencoded; charset=UTF-8;'];
287
    }
288
289
    /**
290
     * @param string $delimiter
291
     * @return $this
292
     */
293
    protected function buildFilePostData($delimiter)
294
    {
295
        $data = "--$delimiter\r\n";
296
        $data .= 'Content-Disposition: form-data; name="img"; filename="' . basename($this->filePathToUpload) . '"' . "\r\n";
297
        $data .= 'Content-Type: ' . FileHelper::getMimeType($this->filePathToUpload) . "\r\n\r\n";
298
        $data .= file_get_contents($this->filePathToUpload) . "\r\n";
299
        $data .= "--$delimiter--\r\n";
300
301
        $this->postFileData = $data;
302
303
        return $this;
304
    }
305
306
    /**
307
     * @return array
308
     */
309
    protected function makeHeadersForUpload()
310
    {
311
        $delimiter = '-------------' . uniqid();
312
        $this->buildFilePostData($delimiter);
313
314
        return [
315
            'Content-Type: multipart/form-data; boundary=' . $delimiter,
316
            'Content-Length: ' . strlen($this->postFileData)
317
        ];
318
    }
319
320
    /**
321
     * @return HttpClient
322
     */
323
    public function getHttpClient()
324
    {
325
        return $this->httpClient;
326
    }
327
328
    /**
329
     * @return string
330
     */
331
    public function getCurrentUrl()
332
    {
333
        return $this->httpClient->getCurrentUrl();
334
    }
335
336
    /**
337
     * @return $this
338
     */
339
    public function dropCookies()
340
    {
341
        $this->httpClient->removeCookies();
342
        $this->clearToken();
343
344
        return $this;
345
    }
346
}
347