Completed
Push — master ( f9a46b...2f170f )
by Sergey
06:17 queued 03:12
created

Request::setUserAgent()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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