GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( f0ae2f...a3df97 )
by Abraham
21s queued 15s
created

TwitterOAuth::mediaInitParameters()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 15
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 10
nc 4
nop 1
1
<?php
2
/**
3
 * The most popular PHP library for use with the Twitter OAuth REST API.
4
 *
5
 * @license MIT
6
 */
7
namespace Abraham\TwitterOAuth;
8
9
use Abraham\TwitterOAuth\Util\JsonDecoder;
10
11
/**
12
 * TwitterOAuth class for interacting with the Twitter API.
13
 *
14
 * @author Abraham Williams <[email protected]>
15
 */
16
class TwitterOAuth extends Config
17
{
18
    const API_VERSION = '1.1';
19
    const API_HOST = 'https://api.twitter.com';
20
    const UPLOAD_HOST = 'https://upload.twitter.com';
21
    const UPLOAD_CHUNK = 40960; // 1024 * 40
22
23
    /** @var Response details about the result of the last request */
24
    private $response;
25
    /** @var string|null Application bearer token */
26
    private $bearer;
27
    /** @var Consumer Twitter application details */
28
    private $consumer;
29
    /** @var Token|null User access token details */
30
    private $token;
31
    /** @var HmacSha1 OAuth 1 signature type used by Twitter */
32
    private $signatureMethod;
33
34
    /**
35
     * Constructor
36
     *
37
     * @param string      $consumerKey      The Application Consumer Key
38
     * @param string      $consumerSecret   The Application Consumer Secret
39
     * @param string|null $oauthToken       The Client Token (optional)
40
     * @param string|null $oauthTokenSecret The Client Token Secret (optional)
41
     */
42
    public function __construct($consumerKey, $consumerSecret, $oauthToken = null, $oauthTokenSecret = null)
43
    {
44
        $this->resetLastResponse();
45
        $this->signatureMethod = new HmacSha1();
46
        $this->consumer = new Consumer($consumerKey, $consumerSecret);
47
        if (!empty($oauthToken) && !empty($oauthTokenSecret)) {
48
            $this->token = new Token($oauthToken, $oauthTokenSecret);
49
        }
50
        if (empty($oauthToken) && !empty($oauthTokenSecret)) {
51
            $this->bearer = $oauthTokenSecret;
52
        }
53
    }
54
55
    /**
56
     * @param string $oauthToken
57
     * @param string $oauthTokenSecret
58
     */
59
    public function setOauthToken($oauthToken, $oauthTokenSecret)
60
    {
61
        $this->token = new Token($oauthToken, $oauthTokenSecret);
62
    }
63
64
    /**
65
     * @return string|null
66
     */
67
    public function getLastApiPath()
68
    {
69
        return $this->response->getApiPath();
70
    }
71
72
    /**
73
     * @return int
74
     */
75
    public function getLastHttpCode()
76
    {
77
        return $this->response->getHttpCode();
78
    }
79
80
    /**
81
     * @return array
82
     */
83
    public function getLastXHeaders()
84
    {
85
        return $this->response->getXHeaders();
86
    }
87
88
    /**
89
     * @return array|object|null
90
     */
91
    public function getLastBody()
92
    {
93
        return $this->response->getBody();
94
    }
95
96
    /**
97
     * Resets the last response cache.
98
     */
99
    public function resetLastResponse()
100
    {
101
        $this->response = new Response();
102
    }
103
104
    /**
105
     * Make URLs for user browser navigation.
106
     *
107
     * @param string $path
108
     * @param array  $parameters
109
     *
110
     * @return string
111
     */
112
    public function url($path, array $parameters)
113
    {
114
        $this->resetLastResponse();
115
        $this->response->setApiPath($path);
116
        $query = http_build_query($parameters);
117
        return sprintf('%s/%s?%s', self::API_HOST, $path, $query);
118
    }
119
120
    /**
121
     * Make /oauth/* requests to the API.
122
     *
123
     * @param string $path
124
     * @param array  $parameters
125
     *
126
     * @return array
127
     * @throws TwitterOAuthException
128
     */
129
    public function oauth($path, array $parameters = [])
130
    {
131
        $response = [];
132
        $this->resetLastResponse();
133
        $this->response->setApiPath($path);
134
        $url = sprintf('%s/%s', self::API_HOST, $path);
135
        $result = $this->oAuthRequest($url, 'POST', $parameters);
136
137
        if ($this->getLastHttpCode() != 200) {
138
            throw new TwitterOAuthException($result);
139
        }
140
141
        parse_str($result, $response);
142
        $this->response->setBody($response);
0 ignored issues
show
Bug introduced by
It seems like $response can also be of type null; however, Abraham\TwitterOAuth\Response::setBody() does only seem to accept array|object, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
143
144
        return $response;
145
    }
146
147
    /**
148
     * Make /oauth2/* requests to the API.
149
     *
150
     * @param string $path
151
     * @param array  $parameters
152
     *
153
     * @return array|object
154
     */
155
    public function oauth2($path, array $parameters = [])
156
    {
157
        $method = 'POST';
158
        $this->resetLastResponse();
159
        $this->response->setApiPath($path);
160
        $url = sprintf('%s/%s', self::API_HOST, $path);
161
        $request = Request::fromConsumerAndToken($this->consumer, $this->token, $method, $url, $parameters);
162
        $authorization = 'Authorization: Basic ' . $this->encodeAppAuthorization($this->consumer);
163
        $result = $this->request($request->getNormalizedHttpUrl(), $method, $authorization, $parameters);
164
        $response = JsonDecoder::decode($result, $this->decodeJsonAsArray);
165
        $this->response->setBody($response);
166
        return $response;
167
    }
168
169
    /**
170
     * Make GET requests to the API.
171
     *
172
     * @param string $path
173
     * @param array  $parameters
174
     *
175
     * @return array|object
176
     */
177
    public function get($path, array $parameters = [])
178
    {
179
        return $this->http('GET', self::API_HOST, $path, $parameters);
180
    }
181
182
    /**
183
     * Make POST requests to the API.
184
     *
185
     * @param string $path
186
     * @param array  $parameters
187
     *
188
     * @return array|object
189
     */
190
    public function post($path, array $parameters = [])
191
    {
192
        return $this->http('POST', self::API_HOST, $path, $parameters);
193
    }
194
195
    /**
196
     * Make DELETE requests to the API.
197
     *
198
     * @param string $path
199
     * @param array  $parameters
200
     *
201
     * @return array|object
202
     */
203
    public function delete($path, array $parameters = [])
204
    {
205
        return $this->http('DELETE', self::API_HOST, $path, $parameters);
206
    }
207
208
    /**
209
     * Make PUT requests to the API.
210
     *
211
     * @param string $path
212
     * @param array  $parameters
213
     *
214
     * @return array|object
215
     */
216
    public function put($path, array $parameters = [])
217
    {
218
        return $this->http('PUT', self::API_HOST, $path, $parameters);
219
    }
220
221
    /**
222
     * Upload media to upload.twitter.com.
223
     *
224
     * @param string $path
225
     * @param array  $parameters
226
     * @param boolean  $chunked
227
     *
228
     * @return array|object
229
     */
230
    public function upload($path, array $parameters = [], $chunked = false)
231
    {
232
        if ($chunked) {
233
            return $this->uploadMediaChunked($path, $parameters);
234
        } else {
235
            return $this->uploadMediaNotChunked($path, $parameters);
236
        }
237
    }
238
239
    /**
240
     * Private method to upload media (not chunked) to upload.twitter.com.
241
     *
242
     * @param string $path
243
     * @param array  $parameters
244
     *
245
     * @return array|object
246
     */
247
    private function uploadMediaNotChunked($path, array $parameters)
248
    {
249
        $file = file_get_contents($parameters['media']);
250
        $base = base64_encode($file);
251
        $parameters['media'] = $base;
252
        return $this->http('POST', self::UPLOAD_HOST, $path, $parameters);
253
    }
254
255
    /**
256
     * Private method to upload media (chunked) to upload.twitter.com.
257
     *
258
     * @param string $path
259
     * @param array  $parameters
260
     *
261
     * @return array|object
262
     */
263
    private function uploadMediaChunked($path, array $parameters)
264
    {
265
        $init = $this->http('POST', self::UPLOAD_HOST, $path, $this->mediaInitParameters($parameters));
266
        // Append
267
        $segment_index = 0;
268
        $media = fopen($parameters['media'], 'rb');
269
        while (!feof($media))
270
        {
271
            $this->http('POST', self::UPLOAD_HOST, 'media/upload', [
272
                'command' => 'APPEND',
273
                'media_id' => $init->media_id_string,
274
                'segment_index' => $segment_index++,
275
                'media_data' => base64_encode(fread($media, self::UPLOAD_CHUNK))
276
            ]);
277
        }
278
        fclose($media);
279
        // Finalize
280
        $finalize = $this->http('POST', self::UPLOAD_HOST, 'media/upload', [
281
            'command' => 'FINALIZE',
282
            'media_id' => $init->media_id_string
283
        ]);
284
        return $finalize;
285
    }
286
287
    /**
288
     * Private method to get params for upload media chunked init.
289
     * Twitter docs: https://dev.twitter.com/rest/reference/post/media/upload-init.html
290
     *
291
     * @param array  $parameters
292
     *
293
     * @return array
294
     */
295
    private function mediaInitParameters(array $parameters)
296
    {
297
        $return = [
298
            'command' => 'INIT',
299
            'media_type' => $parameters['media_type'],
300
            'total_bytes' => filesize($parameters['media'])
301
        ];
302
        if (isset($parameters['additional_owners'])) {
303
            $return['additional_owners'] = $parameters['additional_owners'];
304
        }
305
        if (isset($parameters['media_category'])) {
306
            $return['media_category'] = $parameters['media_category'];
307
        }
308
        return $return;
309
    }
310
311
    /**
312
     * @param string $method
313
     * @param string $host
314
     * @param string $path
315
     * @param array  $parameters
316
     *
317
     * @return array|object
318
     */
319
    private function http($method, $host, $path, array $parameters)
320
    {
321
        $this->resetLastResponse();
322
        $url = sprintf('%s/%s/%s.json', $host, self::API_VERSION, $path);
323
        $this->response->setApiPath($path);
324
        $result = $this->oAuthRequest($url, $method, $parameters);
325
        $response = JsonDecoder::decode($result, $this->decodeJsonAsArray);
326
        $this->response->setBody($response);
327
        return $response;
328
    }
329
330
    /**
331
     * Format and sign an OAuth / API request
332
     *
333
     * @param string $url
334
     * @param string $method
335
     * @param array  $parameters
336
     *
337
     * @return string
338
     * @throws TwitterOAuthException
339
     */
340
    private function oAuthRequest($url, $method, array $parameters)
341
    {
342
        $request = Request::fromConsumerAndToken($this->consumer, $this->token, $method, $url, $parameters);
343
        if (array_key_exists('oauth_callback', $parameters)) {
344
            // Twitter doesn't like oauth_callback as a parameter.
345
            unset($parameters['oauth_callback']);
346
        }
347
        if ($this->bearer === null) {
348
            $request->signRequest($this->signatureMethod, $this->consumer, $this->token);
349
            $authorization = $request->toHeader();
350
        } else {
351
            $authorization = 'Authorization: Bearer ' . $this->bearer;
352
        }
353
        return $this->request($request->getNormalizedHttpUrl(), $method, $authorization, $parameters);
354
    }
355
356
    /**
357
     * Make an HTTP request
358
     *
359
     * @param string $url
360
     * @param string $method
361
     * @param string $authorization
362
     * @param array $postfields
363
     *
364
     * @return string
365
     * @throws TwitterOAuthException
366
     */
367
    private function request($url, $method, $authorization, array $postfields)
368
    {
369
        /* Curl settings */
370
        $options = [
371
            // CURLOPT_VERBOSE => true,
372
            CURLOPT_CAINFO => __DIR__ . DIRECTORY_SEPARATOR . 'cacert.pem',
373
            CURLOPT_CONNECTTIMEOUT => $this->connectionTimeout,
374
            CURLOPT_HEADER => true,
375
            CURLOPT_HTTPHEADER => ['Accept: application/json', $authorization, 'Expect:'],
376
            CURLOPT_RETURNTRANSFER => true,
377
            CURLOPT_SSL_VERIFYHOST => 2,
378
            CURLOPT_SSL_VERIFYPEER => true,
379
            CURLOPT_TIMEOUT => $this->timeout,
380
            CURLOPT_URL => $url,
381
            CURLOPT_USERAGENT => $this->userAgent,
382
        ];
383
384
        /* Remove CACert file when in a PHAR file. */
385
        if ($this->pharRunning()) {
386
            unset($options[CURLOPT_CAINFO]);
387
        }
388
389
        if($this->gzipEncoding) {
390
            $options[CURLOPT_ENCODING] = 'gzip';
391
        }
392
393
        if (!empty($this->proxy)) {
394
            $options[CURLOPT_PROXY] = $this->proxy['CURLOPT_PROXY'];
395
            $options[CURLOPT_PROXYUSERPWD] = $this->proxy['CURLOPT_PROXYUSERPWD'];
396
            $options[CURLOPT_PROXYPORT] = $this->proxy['CURLOPT_PROXYPORT'];
397
            $options[CURLOPT_PROXYAUTH] = CURLAUTH_BASIC;
398
            $options[CURLOPT_PROXYTYPE] = CURLPROXY_HTTP;
399
        }
400
401
        switch ($method) {
402
            case 'GET':
403
                break;
404
            case 'POST':
405
                $options[CURLOPT_POST] = true;
406
                $options[CURLOPT_POSTFIELDS] = Util::buildHttpQuery($postfields);
407
                break;
408
            case 'DELETE':
409
                $options[CURLOPT_CUSTOMREQUEST] = 'DELETE';
410
                break;
411
            case 'PUT':
412
                $options[CURLOPT_CUSTOMREQUEST] = 'PUT';
413
                break;
414
        }
415
416
        if (in_array($method, ['GET', 'PUT', 'DELETE']) && !empty($postfields)) {
417
            $options[CURLOPT_URL] .= '?' . Util::buildHttpQuery($postfields);
418
        }
419
420
421
        $curlHandle = curl_init();
422
        curl_setopt_array($curlHandle, $options);
423
        $response = curl_exec($curlHandle);
424
425
        // Throw exceptions on cURL errors.
426
        if (curl_errno($curlHandle) > 0) {
427
            throw new TwitterOAuthException(curl_error($curlHandle), curl_errno($curlHandle));
428
        }
429
430
        $this->response->setHttpCode(curl_getinfo($curlHandle, CURLINFO_HTTP_CODE));
431
        $parts = explode("\r\n\r\n", $response);
432
        $responseBody = array_pop($parts);
433
        $responseHeader = array_pop($parts);
434
        $this->response->setHeaders($this->parseHeaders($responseHeader));
435
436
        curl_close($curlHandle);
437
438
        return $responseBody;
439
    }
440
441
    /**
442
     * Get the header info to store.
443
     *
444
     * @param string $header
445
     *
446
     * @return array
447
     */
448
    private function parseHeaders($header)
449
    {
450
        $headers = [];
451
        foreach (explode("\r\n", $header) as $line) {
452
            if (strpos($line, ':') !== false) {
453
                list ($key, $value) = explode(': ', $line);
454
                $key = str_replace('-', '_', strtolower($key));
455
                $headers[$key] = trim($value);
456
            }
457
        }
458
        return $headers;
459
    }
460
461
    /**
462
     * Encode application authorization header with base64.
463
     *
464
     * @param Consumer $consumer
465
     *
466
     * @return string
467
     */
468
    private function encodeAppAuthorization(Consumer $consumer)
469
    {
470
        $key = rawurlencode($consumer->key);
471
        $secret = rawurlencode($consumer->secret);
472
        return base64_encode($key . ':' . $secret);
473
    }
474
475
    /**
476
     * Is the code running from a Phar module.
477
     *
478
     * @return boolean
479
     */
480
    private function pharRunning()
481
    {
482
        return class_exists('Phar') && \Phar::running(false) !== '';
483
    }
484
}
485