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
Pull Request — master (#596)
by
unknown
01:28
created

TwitterOAuth::setApiVersion()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
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
    protected $api_version = '1.1';
19
    protected $api_host = 'https://api.twitter.com';
20
    protected $upload_host = 'https://upload.twitter.com';
21
22
    /** @var Response details about the result of the last request */
23
    private $response;
24
    /** @var string|null Application bearer token */
25
    private $bearer;
26
    /** @var Consumer Twitter application details */
27
    private $consumer;
28
    /** @var Token|null User access token details */
29
    private $token;
30
    /** @var HmacSha1 OAuth 1 signature type used by Twitter */
31
    private $signatureMethod;
32
33
    /**
34
     * Constructor
35
     *
36
     * @param string      $consumerKey      The Application Consumer Key
37
     * @param string      $consumerSecret   The Application Consumer Secret
38
     * @param string|null $oauthToken       The Client Token (optional)
39
     * @param string|null $oauthTokenSecret The Client Token Secret (optional)
40
     */
41
    public function __construct($consumerKey, $consumerSecret, $oauthToken = null, $oauthTokenSecret = null)
42
    {
43
        $this->resetLastResponse();
44
        $this->signatureMethod = new HmacSha1();
45
        $this->consumer = new Consumer($consumerKey, $consumerSecret);
46
        if (!empty($oauthToken) && !empty($oauthTokenSecret)) {
47
            $this->token = new Token($oauthToken, $oauthTokenSecret);
48
        }
49
        if (empty($oauthToken) && !empty($oauthTokenSecret)) {
50
            $this->bearer = $oauthTokenSecret;
51
        }
52
    }
53
54
    /**
55
     * @param string $oauthToken
56
     * @param string $oauthTokenSecret
57
     */
58
    public function setOauthToken($oauthToken, $oauthTokenSecret)
59
    {
60
        $this->token = new Token($oauthToken, $oauthTokenSecret);
61
    }
62
63
    /**
64
     * @return string|null
65
     */
66
    public function getLastApiPath()
67
    {
68
        return $this->response->getApiPath();
69
    }
70
71
    /**
72
     * @return int
73
     */
74
    public function getLastHttpCode()
75
    {
76
        return $this->response->getHttpCode();
77
    }
78
79
    /**
80
     * @return array
81
     */
82
    public function getLastXHeaders()
83
    {
84
        return $this->response->getXHeaders();
85
    }
86
87
    /**
88
     * @return array|object|null
89
     */
90
    public function getLastBody()
91
    {
92
        return $this->response->getBody();
93
    }
94
95
    /**
96
     * Resets the last response cache.
97
     */
98
    public function resetLastResponse()
99
    {
100
        $this->response = new Response();
101
    }
102
103
    /**
104
     * Make URLs for user browser navigation.
105
     *
106
     * @param string $path
107
     * @param array  $parameters
108
     *
109
     * @return string
110
     */
111
    public function url($path, array $parameters)
112
    {
113
        $this->resetLastResponse();
114
        $this->response->setApiPath($path);
115
        $query = http_build_query($parameters);
116
        return sprintf('%s/%s?%s', $this->api_host, $path, $query);
117
    }
118
119
    /**
120
     * Make /oauth/* requests to the API.
121
     *
122
     * @param string $path
123
     * @param array  $parameters
124
     *
125
     * @return array
126
     * @throws TwitterOAuthException
127
     */
128
    public function oauth($path, array $parameters = [])
129
    {
130
        $response = [];
131
        $this->resetLastResponse();
132
        $this->response->setApiPath($path);
133
        $url = sprintf('%s/%s', $this->api_host, $path);
134
        $result = $this->oAuthRequest($url, 'POST', $parameters);
135
136
        if ($this->getLastHttpCode() != 200) {
137
            throw new TwitterOAuthException($result);
138
        }
139
140
        parse_str($result, $response);
141
        $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...
142
143
        return $response;
144
    }
145
146
    /**
147
     * Make /oauth2/* requests to the API.
148
     *
149
     * @param string $path
150
     * @param array  $parameters
151
     *
152
     * @return array|object
153
     */
154
    public function oauth2($path, array $parameters = [])
155
    {
156
        $method = 'POST';
157
        $this->resetLastResponse();
158
        $this->response->setApiPath($path);
159
        $url = sprintf('%s/%s', $this->api_host, $path);
160
        $request = Request::fromConsumerAndToken($this->consumer, $this->token, $method, $url, $parameters);
161
        $authorization = 'Authorization: Basic ' . $this->encodeAppAuthorization($this->consumer);
162
        $result = $this->request($request->getNormalizedHttpUrl(), $method, $authorization, $parameters);
163
        $response = JsonDecoder::decode($result, $this->decodeJsonAsArray);
164
        $this->response->setBody($response);
165
        return $response;
166
    }
167
168
    /**
169
     * Make GET requests to the API.
170
     *
171
     * @param string $path
172
     * @param array  $parameters
173
     *
174
     * @return array|object
175
     */
176
    public function get($path, array $parameters = [])
177
    {
178
        return $this->http('GET', $this->api_host, $path, $parameters);
179
    }
180
181
    /**
182
     * Make POST requests to the API.
183
     *
184
     * @param string $path
185
     * @param array  $parameters
186
     *
187
     * @return array|object
188
     */
189
    public function post($path, array $parameters = [])
190
    {
191
        return $this->http('POST', $this->api_host, $path, $parameters);
192
    }
193
194
    /**
195
     * Make DELETE requests to the API.
196
     *
197
     * @param string $path
198
     * @param array  $parameters
199
     *
200
     * @return array|object
201
     */
202
    public function delete($path, array $parameters = [])
203
    {
204
        return $this->http('DELETE', $this->api_host, $path, $parameters);
205
    }
206
207
    /**
208
     * Make PUT requests to the API.
209
     *
210
     * @param string $path
211
     * @param array  $parameters
212
     *
213
     * @return array|object
214
     */
215
    public function put($path, array $parameters = [])
216
    {
217
        return $this->http('PUT', $this->api_host, $path, $parameters);
218
    }
219
220
    /**
221
     * Upload media to upload.twitter.com.
222
     *
223
     * @param string $path
224
     * @param array  $parameters
225
     * @param boolean  $chunked
226
     *
227
     * @return array|object
228
     */
229
    public function upload($path, array $parameters = [], $chunked = false)
230
    {
231
        if ($chunked) {
232
            return $this->uploadMediaChunked($path, $parameters);
233
        } else {
234
            return $this->uploadMediaNotChunked($path, $parameters);
235
        }
236
    }
237
    
238
    /**
239
     * Set Twitter API version
240
     *
241
     * @param string $api_version
242
     *
243
     * @return array|object
244
     */
245
    public function setApiVersion($api_version)
246
    {
247
        $this->api_version = $api_version;
248
    }
249
    
250
    /**
251
     * Set Twitter API endPoint
252
     *
253
     * @param string $api_host
254
     *
255
     * @return array|object
256
     */
257
    public function setApiHost($api_host)
258
    {
259
        $this->api_host = $api_host;
260
    }
261
    
262
    /**
263
     * Set Twitter API upload endPoint
264
     *
265
     * @param string $upload_host
266
     *
267
     * @return array|object
268
     */
269
    public function setUploadHost($upload_host)
270
    {
271
        $this->upload_host = $upload_host;
272
    }
273
274
    /**
275
     * Private method to upload media (not chunked) to upload.twitter.com.
276
     *
277
     * @param string $path
278
     * @param array  $parameters
279
     *
280
     * @return array|object
281
     */
282
    private function uploadMediaNotChunked($path, array $parameters)
283
    {
284
        $file = file_get_contents($parameters['media']);
285
        $base = base64_encode($file);
286
        $parameters['media'] = $base;
287
        return $this->http('POST', $this->upload_host, $path, $parameters);
288
    }
289
290
    /**
291
     * Private method to upload media (chunked) to upload.twitter.com.
292
     *
293
     * @param string $path
294
     * @param array  $parameters
295
     *
296
     * @return array|object
297
     */
298
    private function uploadMediaChunked($path, array $parameters)
299
    {
300
        $init = $this->http('POST', $this->upload_host, $path, $this->mediaInitParameters($parameters));
301
        // Append
302
        $segmentIndex = 0;
303
        $media = fopen($parameters['media'], 'rb');
304
        while (!feof($media))
305
        {
306
            $this->http('POST', $this->upload_host, 'media/upload', [
307
                'command' => 'APPEND',
308
                'media_id' => $init->media_id_string,
309
                'segment_index' => $segmentIndex++,
310
                'media_data' => base64_encode(fread($media, $this->chunkSize))
311
            ]);
312
        }
313
        fclose($media);
314
        // Finalize
315
        $finalize = $this->http('POST', $this->upload_host, 'media/upload', [
316
            'command' => 'FINALIZE',
317
            'media_id' => $init->media_id_string
318
        ]);
319
        return $finalize;
320
    }
321
322
    /**
323
     * Private method to get params for upload media chunked init.
324
     * Twitter docs: https://dev.twitter.com/rest/reference/post/media/upload-init.html
325
     *
326
     * @param array  $parameters
327
     *
328
     * @return array
329
     */
330
    private function mediaInitParameters(array $parameters)
331
    {
332
        $return = [
333
            'command' => 'INIT',
334
            'media_type' => $parameters['media_type'],
335
            'total_bytes' => filesize($parameters['media'])
336
        ];
337
        if (isset($parameters['additional_owners'])) {
338
            $return['additional_owners'] = $parameters['additional_owners'];
339
        }
340
        if (isset($parameters['media_category'])) {
341
            $return['media_category'] = $parameters['media_category'];
342
        }
343
        return $return;
344
    }
345
346
    /**
347
     * @param string $method
348
     * @param string $host
349
     * @param string $path
350
     * @param array  $parameters
351
     *
352
     * @return array|object
353
     */
354
    private function http($method, $host, $path, array $parameters)
355
    {
356
        $this->resetLastResponse();
357
        $url = sprintf('%s/%s/%s.json', $host, $this->api_version, $path);
358
        $this->response->setApiPath($path);
359
        $result = $this->oAuthRequest($url, $method, $parameters);
360
        $response = JsonDecoder::decode($result, $this->decodeJsonAsArray);
361
        $this->response->setBody($response);
362
        return $response;
363
    }
364
365
    /**
366
     * Format and sign an OAuth / API request
367
     *
368
     * @param string $url
369
     * @param string $method
370
     * @param array  $parameters
371
     *
372
     * @return string
373
     * @throws TwitterOAuthException
374
     */
375
    private function oAuthRequest($url, $method, array $parameters)
376
    {
377
        $request = Request::fromConsumerAndToken($this->consumer, $this->token, $method, $url, $parameters);
378
        if (array_key_exists('oauth_callback', $parameters)) {
379
            // Twitter doesn't like oauth_callback as a parameter.
380
            unset($parameters['oauth_callback']);
381
        }
382
        if ($this->bearer === null) {
383
            $request->signRequest($this->signatureMethod, $this->consumer, $this->token);
384
            $authorization = $request->toHeader();
385
            if (array_key_exists('oauth_verifier', $parameters)) {
386
                // Twitter doesn't always work with oauth in the body and in the header
387
                // and it's already included in the $authorization header
388
                unset($parameters['oauth_verifier']);
389
            }
390
        } else {
391
            $authorization = 'Authorization: Bearer ' . $this->bearer;
392
        }
393
        return $this->request($request->getNormalizedHttpUrl(), $method, $authorization, $parameters);
394
    }
395
396
    /**
397
     * Set Curl options.
398
     *
399
     * @return array
400
     */
401
    private function curlOptions()
402
    {
403
        $options = [
404
            // CURLOPT_VERBOSE => true,
405
            CURLOPT_CONNECTTIMEOUT => $this->connectionTimeout,
406
            CURLOPT_HEADER => true,
407
            CURLOPT_RETURNTRANSFER => true,
408
            CURLOPT_SSL_VERIFYHOST => 2,
409
            CURLOPT_SSL_VERIFYPEER => true,
410
            CURLOPT_TIMEOUT => $this->timeout,
411
            CURLOPT_USERAGENT => $this->userAgent,
412
        ];
413
414
        if ($this->useCAFile()) {
415
            $options[CURLOPT_CAINFO] = __DIR__ . DIRECTORY_SEPARATOR . 'cacert.pem';
416
        }
417
418
        if($this->gzipEncoding) {
419
            $options[CURLOPT_ENCODING] = 'gzip';
420
        }
421
422
        if (!empty($this->proxy)) {
423
            $options[CURLOPT_PROXY] = $this->proxy['CURLOPT_PROXY'];
424
            $options[CURLOPT_PROXYUSERPWD] = $this->proxy['CURLOPT_PROXYUSERPWD'];
425
            $options[CURLOPT_PROXYPORT] = $this->proxy['CURLOPT_PROXYPORT'];
426
            $options[CURLOPT_PROXYAUTH] = CURLAUTH_BASIC;
427
            $options[CURLOPT_PROXYTYPE] = CURLPROXY_HTTP;
428
        }
429
430
        return $options;
431
    }
432
433
    /**
434
     * Make an HTTP request
435
     *
436
     * @param string $url
437
     * @param string $method
438
     * @param string $authorization
439
     * @param array $postfields
440
     *
441
     * @return string
442
     * @throws TwitterOAuthException
443
     */
444
    private function request($url, $method, $authorization, array $postfields)
445
    {
446
        $options = $this->curlOptions($url, $authorization);
0 ignored issues
show
Unused Code introduced by
The call to TwitterOAuth::curlOptions() has too many arguments starting with $url.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
447
        $options[CURLOPT_URL] = $url;
448
        $options[CURLOPT_HTTPHEADER] = ['Accept: application/json', $authorization, 'Expect:'];
449
450
        switch ($method) {
451
            case 'GET':
452
                break;
453
            case 'POST':
454
                $options[CURLOPT_POST] = true;
455
                $options[CURLOPT_POSTFIELDS] = Util::buildHttpQuery($postfields);
456
                break;
457
            case 'DELETE':
458
                $options[CURLOPT_CUSTOMREQUEST] = 'DELETE';
459
                break;
460
            case 'PUT':
461
                $options[CURLOPT_CUSTOMREQUEST] = 'PUT';
462
                break;
463
        }
464
465
        if (in_array($method, ['GET', 'PUT', 'DELETE']) && !empty($postfields)) {
466
            $options[CURLOPT_URL] .= '?' . Util::buildHttpQuery($postfields);
467
        }
468
469
470
        $curlHandle = curl_init();
471
        curl_setopt_array($curlHandle, $options);
472
        $response = curl_exec($curlHandle);
473
474
        // Throw exceptions on cURL errors.
475
        if (curl_errno($curlHandle) > 0) {
476
            throw new TwitterOAuthException(curl_error($curlHandle), curl_errno($curlHandle));
477
        }
478
479
        $this->response->setHttpCode(curl_getinfo($curlHandle, CURLINFO_HTTP_CODE));
480
        $parts = explode("\r\n\r\n", $response);
481
        $responseBody = array_pop($parts);
482
        $responseHeader = array_pop($parts);
483
        $this->response->setHeaders($this->parseHeaders($responseHeader));
484
485
        curl_close($curlHandle);
486
487
        return $responseBody;
488
    }
489
490
    /**
491
     * Get the header info to store.
492
     *
493
     * @param string $header
494
     *
495
     * @return array
496
     */
497
    private function parseHeaders($header)
498
    {
499
        $headers = [];
500
        foreach (explode("\r\n", $header) as $line) {
501
            if (strpos($line, ':') !== false) {
502
                list ($key, $value) = explode(': ', $line);
503
                $key = str_replace('-', '_', strtolower($key));
504
                $headers[$key] = trim($value);
505
            }
506
        }
507
        return $headers;
508
    }
509
510
    /**
511
     * Encode application authorization header with base64.
512
     *
513
     * @param Consumer $consumer
514
     *
515
     * @return string
516
     */
517
    private function encodeAppAuthorization(Consumer $consumer)
518
    {
519
        $key = rawurlencode($consumer->key);
520
        $secret = rawurlencode($consumer->secret);
521
        return base64_encode($key . ':' . $secret);
522
    }
523
524
    /**
525
     * Is the code running from a Phar module.
526
     *
527
     * @return boolean
528
     */
529
    private function pharRunning()
530
    {
531
        return class_exists('Phar') && \Phar::running(false) !== '';
532
    }
533
534
    /**
535
     * Use included CA file instead of OS provided list.
536
     *
537
     * @return boolean
538
     */
539
    private function useCAFile()
540
    {
541
        /* Use CACert file when not in a PHAR file. */
542
        return !$this->pharRunning();
543
    }
544
}
545