Completed
Pull Request — master (#149)
by Sergey
03:11
created

Request::getHttpHeaders()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 9
rs 9.6666
cc 2
eloc 5
nc 2
nop 0
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\HttpClient;
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   $csrfToken
18
 */
19
class Request
20
{
21
    /**
22
     * @var HttpClient
23
     */
24
    protected $httpClient;
25
26
    /**
27
     * @var bool
28
     */
29
    protected $loggedIn;
30
31
    /**
32
     *
33
     * @var string
34
     */
35
    protected $filePathToUpload;
36
37
    /**
38
     * @var string
39
     */
40
    protected $csrfToken = '';
41
42
    /**
43
     * @var string
44
     */
45
    protected $postFileData;
46
47
    /**
48
     * @var array|null
49
     */
50
    protected $lastError;
51
52
53
    /**
54
     * Common headers needed for every query.
55
     *
56
     * @var array
57
     */
58
    protected $requestHeaders = [
59
        'Accept: application/json, text/javascript, */*; q=0.01',
60
        'Accept-Language: en-US,en;q=0.5',
61
        'DNT: 1',
62
        'X-Pinterest-AppState: active',
63
        'X-NEW-APP: 1',
64
        'X-APP-VERSION: 04cf8cc',
65
        'X-Requested-With: XMLHttpRequest',
66
    ];
67
68
    /**
69
     * @param HttpClient $http
70
     */
71
    public function __construct(HttpClient $http)
72
    {
73
        $this->httpClient = $http;
74
        $this->loggedIn = false;
75
    }
76
77
    /**
78
     * @param string $pathToFile
79
     * @param string $url
80
     * @return array
81
     * @throws InvalidRequestException
82
     */
83
    public function upload($pathToFile, $url)
84
    {
85
        $this->filePathToUpload = $pathToFile;
86
87
        return $this->exec($url)->getData();
88
    }
89
90
    /**
91
     * Executes request to Pinterest API.
92
     *
93
     * @param string $resourceUrl
94
     * @param string $postString
95
     *
96
     * @return Response
97
     */
98
    public function exec($resourceUrl, $postString = '')
99
    {
100
        $url = UrlHelper::buildApiUrl($resourceUrl);
101
        $headers = $this->getHttpHeaders();
102
        $postString = $this->filePathToUpload ? $this->postFileData : $postString;
103
104
        $result = $this
105
            ->httpClient
106
            ->execute($url, $postString, $headers);
107
108
        return $this->processResponse($result);
109
    }
110
111
    /**
112
     * @return array
113
     */
114
    protected function getHttpHeaders()
115
    {
116
        $headers = $this->getDefaultHttpHeaders();
117
        if ($this->csrfToken == CsrfHelper::DEFAULT_TOKEN) {
118
            $headers[] = CsrfHelper::getDefaultCookie();
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 = CsrfHelper::DEFAULT_TOKEN;
133
134
        return $this;
135
    }
136
137
    /**
138
     * Mark api as logged.
139
     * @return $this
140
     * @throws AuthException
141
     */
142
    public function login()
143
    {
144
        $this->setTokenFromCookies();
145
        $this->loggedIn = true;
146
    }
147
148
    public function logout()
149
    {
150
        $this->clearToken();
151
        $this->loggedIn = false;
152
    }
153
154
    /**
155
     * Get log status.
156
     *
157
     * @return bool
158
     */
159
    public function isLoggedIn()
160
    {
161
        return $this->loggedIn;
162
    }
163
164
    /**
165
     * Create request string.
166
     *
167
     * @param array  $data
168
     * @param array  $bookmarks
169
     *
170
     * @return string
171
     */
172
    public static function createQuery(array $data = [], $bookmarks = [])
173
    {
174
        $data = ['options' => $data];
175
        $request = self::createRequestData($data, $bookmarks);
176
177
        return UrlHelper::buildRequestString($request);
178
    }
179
180
    /**
181
     * @param array|object $data
182
     * @param array        $bookmarks
183
     *
184
     * @return array
185
     */
186
    public static function createRequestData(array $data = [], $bookmarks = [])
187
    {
188
        if (empty($data)) {
189
            $data = ['options' => []];
190
        }
191
192
        if (!empty($bookmarks)) {
193
            $data['options']['bookmarks'] = $bookmarks;
194
        }
195
196
        $data['context'] = new \stdClass();
197
198
        return [
199
            'source_url' => '',
200
            'data'       => json_encode($data),
201
        ];
202
    }
203
204
    public function setTokenFromCookies()
205
    {
206
        $this->csrfToken = $this->httpClient->getToken();
207
        if (empty($this->csrfToken)) {
208
            throw new AuthException('Cannot parse token from cookies.');
209
        }
210
211
        return $this;
212
    }
213
214
    /**
215
     * @return array
216
     */
217
    protected function getDefaultHttpHeaders()
218
    {
219
        return array_merge(
220
            $this->requestHeaders,
221
            $this->getContentTypeHeader(),
222
            [
223
                'Host: ' . UrlHelper::HOST,
224
                'X-CSRFToken: ' . $this->csrfToken
225
            ]
226
        );
227
    }
228
229
    /**
230
     * If we are uploading file, we should build boundary form data. Otherwise
231
     * it is simple urlencoded form.
232
     *
233
     * @return array
234
     */
235
    protected function getContentTypeHeader()
236
    {
237
        return $this->filePathToUpload ?
238
            $this->makeHeadersForUpload() :
239
            ['Content-Type: application/x-www-form-urlencoded; charset=UTF-8;'];
240
    }
241
242
    /**
243
     * @param string $delimiter
244
     * @return $this
245
     */
246
    protected function buildFilePostData($delimiter)
247
    {
248
        $data = "--$delimiter\r\n";
249
        $data .= 'Content-Disposition: form-data; name="img"; filename="' . basename($this->filePathToUpload) . '"' . "\r\n";
250
        $data .= 'Content-Type: ' . FileHelper::getMimeType($this->filePathToUpload) . "\r\n\r\n";
251
        $data .= file_get_contents($this->filePathToUpload) . "\r\n";
252
        $data .= "--$delimiter--\r\n";
253
254
        $this->postFileData = $data;
255
256
        return $this;
257
    }
258
259
    protected function makeHeadersForUpload()
260
    {
261
        $delimiter = '-------------' . uniqid();
262
        $this->buildFilePostData($delimiter);
263
264
        return [
265
            'Content-Type: multipart/form-data; boundary=' . $delimiter,
266
            'Content-Length: ' . strlen($this->postFileData)
267
        ];
268
    }
269
270
    /**
271
     * @param string $res
272
     * @return Response
273
     */
274
    protected function processResponse($res)
275
    {
276
        $this->filePathToUpload = null;
277
        $this->lastError = null;
278
279
        $response = new Response(json_decode($res, true));
280
        $this->lastError = $response->getLastError();
281
282
        return $response;
283
    }
284
285
    /**
286
     * @return array|null
287
     */
288
    public function getLastError()
289
    {
290
        return $this->lastError;
291
    }
292
293
    /**
294
     * @return HttpClient
295
     */
296
    public function getHttpClient()
297
    {
298
        return $this->httpClient;
299
    }
300
}
301