Completed
Push — master ( 87209a...672fdc )
by Sergey
01:08
created

Request::processResponse()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 10
rs 9.4285
cc 1
eloc 6
nc 1
nop 1
1
<?php
2
3
namespace seregazhuk\PinterestBot\Api;
4
5
use seregazhuk\PinterestBot\Exceptions\InvalidRequestException;
6
use seregazhuk\PinterestBot\Helpers\UrlHelper;
7
use seregazhuk\PinterestBot\Api\Contracts\Http;
8
use seregazhuk\PinterestBot\Helpers\FileHelper;
9
use seregazhuk\PinterestBot\Helpers\CsrfHelper;
10
use seregazhuk\PinterestBot\Exceptions\AuthException;
11
12
/**
13
 * Class Request.
14
 *
15
 * @property resource $ch
16
 * @property bool     $loggedIn
17
 * @property string   $userAgent
18
 * @property string   $csrfToken
19
 * @property string   $cookieJar
20
 */
21
class Request
22
{
23
    const COOKIE_NAME = 'pinterest_cookie';
24
25
    /**
26
     * @var string
27
     */
28
    protected $userAgent = 'Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Firefox/31.0';
29
30
    /**
31
     * @var Http
32
     */
33
    protected $http;
34
35
    /**
36
     * @var bool
37
     */
38
    protected $loggedIn;
39
40
    /**
41
     * @var string
42
     */
43
    protected $cookieJar;
44
45
    /**
46
     * @var array
47
     */
48
    protected $options;
49
50
    /**
51
     *
52
     * @var string
53
     */
54
    protected $filePathToUpload;
55
56
    /**
57
     * @var string
58
     */
59
    protected $csrfToken = '';
60
61
    /**
62
     * @var string
63
     */
64
    protected $postFileData;
65
66
    /**
67
     * @var array|null
68
     */
69
    protected $lastError;
70
71
72
    /**
73
     * Common headers needed for every query.
74
     *
75
     * @var array
76
     */
77
    protected $requestHeaders = [
78
        'Accept: application/json, text/javascript, */*; q=0.01',
79
        'Accept-Language: en-US,en;q=0.5',
80
        'DNT: 1',
81
        'X-Pinterest-AppState: active',
82
        'X-NEW-APP: 1',
83
        'X-APP-VERSION: 04cf8cc',
84
        'X-Requested-With: XMLHttpRequest',
85
    ];
86
87
    /**
88
     * @param Http $http
89
     */
90
    public function __construct(Http $http)
91
    {
92
        $this->http = $http;
93
        $this->loggedIn = false;
94
        $this->cookieJar = tempnam(sys_get_temp_dir(), self::COOKIE_NAME);
95
    }
96
97
    /**
98
     * @param string $pathToFile
99
     * @param string $url
100
     * @return array
101
     * @throws InvalidRequestException
102
     */
103
    public function upload($pathToFile, $url)
104
    {
105
        $this->filePathToUpload = $pathToFile;
106
        return $this->exec($url);
107
    }
108
109
    /**
110
     * Executes request to Pinterest API.
111
     *
112
     * @param string $resourceUrl
113
     * @param string $postString
114
     *
115
     * @return Response
116
     */
117
    public function exec($resourceUrl, $postString = '')
118
    {
119
        $url = UrlHelper::buildApiUrl($resourceUrl);
120
        $this->makeHttpOptions($postString);
121
122
        $result = $this
123
            ->http
124
            ->execute($url, $this->options);
125
126
        return $this->processResponse($result);
0 ignored issues
show
Documentation introduced by
$result is of type string, but the function expects a array|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
127
    }
128
129
    /**
130
     * Adds necessary curl options for query.
131
     *
132
     * @param string $postString POST query string
133
     *
134
     * @return $this
135
     */
136
    protected function makeHttpOptions($postString = '')
137
    {
138
        $this->setDefaultHttpOptions();
139
140
        if ($this->csrfToken == CsrfHelper::DEFAULT_TOKEN) {
141
            $this->options = $this->addDefaultCsrfInfo($this->options);
142
        }
143
144
        if (!empty($postString) || $this->filePathToUpload) {
145
            $this->options[CURLOPT_POST] = true;
146
            $this->options[CURLOPT_POSTFIELDS] = $this->filePathToUpload ? $this->postFileData : $postString;
147
        }
148
149
        return $this;
150
    }
151
152
    /**
153
     * @return array
154
     */
155
    protected function setDefaultHttpOptions()
156
    {
157
        $this->options = [
158
            CURLOPT_USERAGENT      => $this->userAgent,
159
            CURLOPT_RETURNTRANSFER => true,
160
            CURLOPT_SSL_VERIFYPEER => false,
161
            CURLOPT_FOLLOWLOCATION => true,
162
            CURLOPT_ENCODING       => 'gzip,deflate',
163
            CURLOPT_HTTPHEADER     => $this->getDefaultHttpHeaders(),
164
            CURLOPT_REFERER        => UrlHelper::URL_BASE,
165
            CURLOPT_COOKIEFILE     => $this->cookieJar,
166
            CURLOPT_COOKIEJAR      => $this->cookieJar,
167
        ];
168
    }
169
170
    /**
171
     * @param array $options
172
     *
173
     * @return mixed
174
     */
175
    protected function addDefaultCsrfInfo($options)
176
    {
177
        $options[CURLOPT_REFERER] = UrlHelper::URL_BASE;
178
        $options[CURLOPT_HTTPHEADER][] = CsrfHelper::getDefaultCookie();
179
180
        return $options;
181
    }
182
    
183
    /**
184
     * Clear token information.
185
     *
186
     * @return $this
187
     */
188
    public function clearToken()
189
    {
190
        $this->csrfToken = CsrfHelper::DEFAULT_TOKEN;
191
192
        return $this;
193
    }
194
195
    /**
196
     * Mark api as logged.
197
     * @return $this
198
     * @throws AuthException
199
     */
200
    public function login()
201
    {
202
        $this->setTokenFromCookies();
203
        $this->loggedIn = true;
204
    }
205
206
    public function logout()
207
    {
208
        $this->clearToken();
209
        $this->loggedIn = false;
210
    }
211
212
    /**
213
     * Get log status.
214
     *
215
     * @return bool
216
     */
217
    public function isLoggedIn()
218
    {
219
        return $this->loggedIn;
220
    }
221
222
    /**
223
     * @param $userAgent
224
     * @return $this
225
     */
226
    public function setUserAgent($userAgent)
227
    {
228
        if ($userAgent !== null) {
229
            $this->userAgent = $userAgent;
230
        }
231
232
        return $this;
233
    }
234
235
    /**
236
     * Create request string.
237
     *
238
     * @param array  $data
239
     * @param array  $bookmarks
240
     *
241
     * @return string
242
     */
243
    public static function createQuery(array $data = [], $bookmarks = [])
244
    {
245
        $data = ['options' => $data];
246
        $request = self::createRequestData($data, $bookmarks);
247
248
        return UrlHelper::buildRequestString($request);
249
    }
250
251
    /**
252
     * @param array|object $data
253
     * @param array        $bookmarks
254
     *
255
     * @return array
256
     */
257
    public static function createRequestData(array $data = [], $bookmarks = [])
258
    {
259
        if (empty($data)) {
260
            $data = ['options' => []];
261
        }
262
263
        if (!empty($bookmarks)) {
264
            $data['options']['bookmarks'] = $bookmarks;
265
        }
266
267
        $data['context'] = new \stdClass();
268
269
        return [
270
            'source_url' => '',
271
            'data'       => json_encode($data),
272
        ];
273
    }
274
275
    public function setTokenFromCookies()
276
    {
277
        $this->csrfToken = CsrfHelper::getTokenFromFile($this->cookieJar);
278
        if (empty($this->csrfToken)) {
279
            throw new AuthException('Cannot parse token from cookies.');
280
        }
281
282
        return $this;
283
    }
284
285
    /**
286
     * @return array
287
     */
288
    protected function getDefaultHttpHeaders()
289
    {
290
        return array_merge(
291
            $this->requestHeaders, $this->getContentTypeHeader(), [
292
                'Host: ' . UrlHelper::HOST,
293
                'X-CSRFToken: ' . $this->csrfToken
294
            ]
295
        );
296
    }
297
298
    /**
299
     * If we are uploading file, we should build boundary form data. Otherwise
300
     * it is simple urlencoded form.
301
     *
302
     * @return array
303
     */
304
    protected function getContentTypeHeader()
305
    {
306
        return $this->filePathToUpload ?
307
            $this->makeHeadersForUpload() :
308
            ['Content-Type: application/x-www-form-urlencoded; charset=UTF-8;'];
309
    }
310
311
    /**
312
     * @param string $delimiter
313
     * @return $this
314
     */
315
    protected function buildFilePostData($delimiter)
316
    {
317
        $data = "--$delimiter\r\n";
318
        $data .= 'Content-Disposition: form-data; name="img"; filename="' . basename($this->filePathToUpload) . '"' . "\r\n";
319
        $data .= 'Content-Type: ' . FileHelper::getMimeType($this->filePathToUpload) . "\r\n\r\n";
320
        $data .= file_get_contents($this->filePathToUpload) . "\r\n";
321
        $data .= "--$delimiter--\r\n";
322
323
        $this->postFileData = $data;
324
325
        return $this;
326
    }
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
     * @param array|null $res
341
     * @return Response
342
     */
343
    protected function processResponse($res)
344
    {
345
        $this->filePathToUpload = null;
346
        $this->lastError = null;
347
348
        $response = new Response(json_decode($res, true));
349
        $this->lastError = $response->getLastError();
350
351
        return $response;
352
    }
353
354
    /**
355
     * @return array|null
356
     */
357
    public function getLastError()
358
    {
359
        return $this->lastError;
360
    }
361
}
362