Completed
Push — master ( a6f1c6...fad4ca )
by Sergey
59s
created

Request::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 5
rs 9.4285
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
3
namespace seregazhuk\PinterestBot\Api;
4
5
use seregazhuk\PinterestBot\Helpers\UrlHelper;
6
use seregazhuk\PinterestBot\Helpers\FileHelper;
7
use seregazhuk\PinterestBot\Helpers\CsrfHelper;
8
use seregazhuk\PinterestBot\Contracts\HttpInterface;
9
use seregazhuk\PinterestBot\Exceptions\AuthException;
10
use seregazhuk\PinterestBot\Contracts\RequestInterface;
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 implements RequestInterface
22
{
23
    const COOKIE_NAME = 'pinterest_cookie';
24
25
    protected $userAgent = 'Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Firefox/31.0';
26
    /**
27
     * @var HttpInterface
28
     */
29
    protected $http;
30
    protected $loggedIn;
31
    protected $cookieJar;
32
    protected $options;
33
34
    /**
35
     *
36
     * @var string
37
     */
38
    protected $filePathToUpload;
39
40
    public $csrfToken = '';
41
42
    /**
43
     * Common headers needed for every query.
44
     *
45
     * @var array
46
     */
47
    protected $requestHeaders = [
48
        'Accept: application/json, text/javascript, */*; q=0.01',
49
        'Accept-Language: en-US,en;q=0.5',
50
        'DNT: 1',
51
        'Host: nl.pinterest.com',
52
        'X-Pinterest-AppState: active',
53
        'X-NEW-APP: 1',
54
        'X-APP-VERSION: 04cf8cc',
55
        'X-Requested-With: XMLHttpRequest',
56
    ];
57
58
    /**
59
     * @var string
60
     */
61
    protected $postFileData;
62
63
    /**
64
     * @param HttpInterface $http
65
     */
66
    public function __construct(HttpInterface $http)
67
    {
68
        $this->http = $http;
69
        $this->cookieJar = tempnam(sys_get_temp_dir(), self::COOKIE_NAME);
70
    }
71
72
    /**
73
     * Executes api call for follow or unfollow user.
74
     *
75
     * @param int    $entityId
76
     * @param string $entityName
77
     * @param string $url
78
     *
79
     * @return array
80
     */
81
    public function followMethodCall($entityId, $entityName, $url)
82
    {
83
        $dataJson = [
84
            'options' => [
85
                $entityName => (string)$entityId,
86
            ],
87
            'context' => [],
88
        ];
89
90
        if ($entityName == 'interest_id') {
91
            $dataJson['options']['interest_list'] = 'favorited';
92
        }
93
94
        $post = ['data' => json_encode($dataJson, JSON_FORCE_OBJECT)];
95
        $postString = UrlHelper::buildRequestString($post);
96
97
        return $this->exec($url, $postString);
98
    }
99
100
    public function upload($pathToFile, $url)
101
    {
102
        $this->filePathToUpload = $pathToFile;
103
104
        return $this->exec($url);
105
    }
106
107
    /**
108
     * Executes request to Pinterest API.
109
     *
110
     * @param string $resourceUrl
111
     * @param string $postString
112
     *
113
     * @return array
114
     */
115
    public function exec($resourceUrl, $postString = '')
116
    {
117
        $url = UrlHelper::buildApiUrl($resourceUrl);        
118
        $this->makeHttpOptions($postString);
119
        $res = $this->http->execute($url, $this->options);
120
121
        $this->filePathToUpload = null;
122
        return json_decode($res, true);
123
    }
124
125
    /**
126
     * Adds necessary curl options for query.
127
     *
128
     * @param string $postString POST query string
129
     *
130
     * @return $this
131
     */
132
    protected function makeHttpOptions($postString = '')
133
    {
134
        $this->setDefaultHttpOptions();
135
136
        if ($this->csrfToken == CsrfHelper::DEFAULT_TOKEN) {
137
            $this->options = $this->addDefaultCsrfInfo($this->options);
138
        }
139
140
        if (!empty($postString) || $this->filePathToUpload) {
141
            $this->options[CURLOPT_POST] = true;
142
            $this->options[CURLOPT_POSTFIELDS] = $this->filePathToUpload ? $this->postFileData : $postString;
143
        }
144
145
        return $this;
146
    }
147
148
    /**
149
     * @return array
150
     */
151
    protected function setDefaultHttpOptions()
152
    {
153
        $this->options = [
154
            CURLOPT_USERAGENT      => $this->userAgent,
155
            CURLOPT_RETURNTRANSFER => true,
156
            CURLOPT_SSL_VERIFYPEER => false,
157
            CURLOPT_FOLLOWLOCATION => true,
158
            CURLOPT_ENCODING       => 'gzip,deflate',
159
            CURLOPT_HTTPHEADER     => $this->getDefaultHttpHeaders(),
160
            CURLOPT_REFERER        => UrlHelper::URL_BASE,
161
            CURLOPT_COOKIEFILE     => $this->cookieJar,
162
            CURLOPT_COOKIEJAR      => $this->cookieJar,
163
        ];
164
    }
165
166
    /**
167
     * @param array $options
168
     *
169
     * @return mixed
170
     */
171
    protected function addDefaultCsrfInfo($options)
172
    {
173
        $options[CURLOPT_REFERER] = UrlHelper::URL_BASE;
174
        $options[CURLOPT_HTTPHEADER][] = CsrfHelper::getDefaultCookie();
175
176
        return $options;
177
    }
178
    
179
    /**
180
     * Clear token information.
181
     *
182
     * @return $this
183
     */
184
    public function clearToken()
185
    {
186
        $this->csrfToken = CsrfHelper::DEFAULT_TOKEN;
187
188
        return $this;
189
    }
190
191
    /**
192
     * Mark api as logged.
193
     * @return $this
194
     * @throws AuthException
195
     */
196
    public function setLoggedIn()
197
    {
198
        $this->csrfToken = CsrfHelper::getTokenFromFile($this->cookieJar);
199
        if (empty($this->csrfToken)) {
200
            throw new AuthException('Cannot parse token from cookies.');
201
        }
202
        $this->loggedIn = true;
203
        return $this;
204
    }
205
206
    /**
207
     * Get log status.
208
     *
209
     * @return bool
210
     */
211
    public function isLoggedIn()
212
    {
213
        return $this->loggedIn;
214
    }
215
216
    /**
217
     * @param $userAgent
218
     * @return $this
219
     */
220
    public function setUserAgent($userAgent)
221
    {
222
        if ($userAgent !== null) {
223
            $this->userAgent = $userAgent;
224
        }
225
226
        return $this;
227
    }
228
229
    /**
230
     * Create request string.
231
     *
232
     * @param array  $data
233
     * @param string $sourceUrl
234
     * @param array  $bookmarks
235
     *
236
     * @return string
237
     */
238
    public static function createQuery(array $data = [], $sourceUrl = '/', $bookmarks = [])
239
    {
240
        $request = self::createRequestData($data, $sourceUrl, $bookmarks);
241
242
        return UrlHelper::buildRequestString($request);
243
    }
244
245
    /**
246
     * @param array|object $data
247
     * @param string|null  $sourceUrl
248
     * @param array        $bookmarks
249
     *
250
     * @return array
251
     */
252
    public static function createRequestData(array $data = [], $sourceUrl = '/', $bookmarks = [])
253
    {
254
        if (empty($data)) {
255
            $data = ['options' => []];
256
        }
257
258
        if (!empty($bookmarks)) {
259
            $data['options']['bookmarks'] = $bookmarks;
260
        }
261
262
        $data['context'] = new \stdClass();
263
264
        return [
265
            'source_url' => $sourceUrl,
266
            'data'       => json_encode($data),
267
        ];
268
    }
269
270
    /**
271
     * @return array
272
     */
273
    protected function getDefaultHttpHeaders()
274
    {
275
        return array_merge(
276
            $this->requestHeaders, $this->getContentTypeHeader(), ['X-CSRFToken: ' . $this->csrfToken]
277
        );
278
    }
279
280
    /**
281
     * If we are uploading file, we should build boundary form data. Otherwise
282
     * it is simple urlencoded form.
283
     *
284
     * @return array
285
     */
286
    protected function getContentTypeHeader()
287
    {
288
        if ($this->filePathToUpload) {
289
            $delimiter = '-------------' . uniqid();
290
            $this->buildFilePostData($delimiter);
291
292
            return [
293
                'Content-Type: multipart/form-data; boundary=' . $delimiter,
294
                'Content-Length: ' . strlen($this->postFileData)
295
            ];
296
        }
297
298
        return ['Content-Type: application/x-www-form-urlencoded; charset=UTF-8;'];
299
    }
300
301
    protected function buildFilePostData($delimiter)
302
    {
303
        $data = "--$delimiter\r\n";
304
        $data .= 'Content-Disposition: form-data; name="img"; filename="' . basename($this->filePathToUpload) . '"' . "\r\n";
305
        $data .= 'Content-Type: ' . FileHelper::getMimeType($this->filePathToUpload) . "\r\n\r\n";
306
        $data .= file_get_contents($this->filePathToUpload) . "\r\n";
307
        $data .= "--$delimiter--\r\n";
308
309
        $this->postFileData = $data;
310
311
        return $this;
312
    }
313
}
314