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 ( a76795...56d63a )
by Abraham
11:05
created

TwitterOAuth::getLastApiPath()   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 0
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
266
        $init = $this->http('POST', self::UPLOAD_HOST, $path, [
267
            'command' => 'INIT',
268
            'media_type' => $parameters['media_type'],
269
            'total_bytes' => filesize($parameters['media'])
270
        ]);
271
        // Append
272
        $segment_index = 0;
273
        $media = fopen($parameters['media'], 'rb');
274
        while (!feof($media))
275
        {
276
            $this->http('POST', self::UPLOAD_HOST, 'media/upload', [
277
                'command' => 'APPEND',
278
                'media_id' => $init->media_id_string,
279
                'segment_index' => $segment_index++,
280
                'media_data' => base64_encode(fread($media, self::UPLOAD_CHUNK))
281
            ]);
282
        }
283
        fclose($media);
284
        // Finalize
285
        $finalize = $this->http('POST', self::UPLOAD_HOST, 'media/upload', [
286
            'command' => 'FINALIZE',
287
            'media_id' => $init->media_id_string
288
        ]);
289
        return $finalize;
290
    }
291
292
    /**
293
     * @param string $method
294
     * @param string $host
295
     * @param string $path
296
     * @param array  $parameters
297
     *
298
     * @return array|object
299
     */
300
    private function http($method, $host, $path, array $parameters)
301
    {
302
        $this->resetLastResponse();
303
        $url = sprintf('%s/%s/%s.json', $host, self::API_VERSION, $path);
304
        $this->response->setApiPath($path);
305
        $result = $this->oAuthRequest($url, $method, $parameters);
306
        $response = JsonDecoder::decode($result, $this->decodeJsonAsArray);
307
        $this->response->setBody($response);
308
        return $response;
309
    }
310
311
    /**
312
     * Format and sign an OAuth / API request
313
     *
314
     * @param string $url
315
     * @param string $method
316
     * @param array  $parameters
317
     *
318
     * @return string
319
     * @throws TwitterOAuthException
320
     */
321
    private function oAuthRequest($url, $method, array $parameters)
322
    {
323
        $request = Request::fromConsumerAndToken($this->consumer, $this->token, $method, $url, $parameters);
324
        if (array_key_exists('oauth_callback', $parameters)) {
325
            // Twitter doesn't like oauth_callback as a parameter.
326
            unset($parameters['oauth_callback']);
327
        }
328
        if ($this->bearer === null) {
329
            $request->signRequest($this->signatureMethod, $this->consumer, $this->token);
330
            $authorization = $request->toHeader();
331
        } else {
332
            $authorization = 'Authorization: Bearer ' . $this->bearer;
333
        }
334
        return $this->request($request->getNormalizedHttpUrl(), $method, $authorization, $parameters);
335
    }
336
337
    /**
338
     * Make an HTTP request
339
     *
340
     * @param string $url
341
     * @param string $method
342
     * @param string $authorization
343
     * @param array $postfields
344
     *
345
     * @return string
346
     * @throws TwitterOAuthException
347
     */
348
    private function request($url, $method, $authorization, array $postfields)
349
    {
350
        /* Curl settings */
351
        $options = [
352
            // CURLOPT_VERBOSE => true,
353
            CURLOPT_CAINFO => __DIR__ . DIRECTORY_SEPARATOR . 'cacert.pem',
354
            CURLOPT_CONNECTTIMEOUT => $this->connectionTimeout,
355
            CURLOPT_HEADER => true,
356
            CURLOPT_HTTPHEADER => ['Accept: application/json', $authorization, 'Expect:'],
357
            CURLOPT_RETURNTRANSFER => true,
358
            CURLOPT_SSL_VERIFYHOST => 2,
359
            CURLOPT_SSL_VERIFYPEER => true,
360
            CURLOPT_TIMEOUT => $this->timeout,
361
            CURLOPT_URL => $url,
362
            CURLOPT_USERAGENT => $this->userAgent,
363
        ];
364
365
        /* Remove CACert file when in a PHAR file. */
366
        if ($this->pharRunning()) {
367
            unset($options[CURLOPT_CAINFO]);
368
        }
369
370
        if($this->gzipEncoding) {
371
            $options[CURLOPT_ENCODING] = 'gzip';
372
        }
373
374
        if (!empty($this->proxy)) {
375
            $options[CURLOPT_PROXY] = $this->proxy['CURLOPT_PROXY'];
376
            $options[CURLOPT_PROXYUSERPWD] = $this->proxy['CURLOPT_PROXYUSERPWD'];
377
            $options[CURLOPT_PROXYPORT] = $this->proxy['CURLOPT_PROXYPORT'];
378
            $options[CURLOPT_PROXYAUTH] = CURLAUTH_BASIC;
379
            $options[CURLOPT_PROXYTYPE] = CURLPROXY_HTTP;
380
        }
381
382
        switch ($method) {
383
            case 'GET':
384
                break;
385
            case 'POST':
386
                $options[CURLOPT_POST] = true;
387
                $options[CURLOPT_POSTFIELDS] = Util::buildHttpQuery($postfields);
388
                break;
389
            case 'DELETE':
390
                $options[CURLOPT_CUSTOMREQUEST] = 'DELETE';
391
                break;
392
            case 'PUT':
393
                $options[CURLOPT_CUSTOMREQUEST] = 'PUT';
394
                break;
395
        }
396
397
        if (in_array($method, ['GET', 'PUT', 'DELETE']) && !empty($postfields)) {
398
            $options[CURLOPT_URL] .= '?' . Util::buildHttpQuery($postfields);
399
        }
400
401
402
        $curlHandle = curl_init();
403
        curl_setopt_array($curlHandle, $options);
404
        $response = curl_exec($curlHandle);
405
406
        // Throw exceptions on cURL errors.
407
        if (curl_errno($curlHandle) > 0) {
408
            throw new TwitterOAuthException(curl_error($curlHandle), curl_errno($curlHandle));
409
        }
410
411
        $this->response->setHttpCode(curl_getinfo($curlHandle, CURLINFO_HTTP_CODE));
412
        $parts = explode("\r\n\r\n", $response);
413
        $responseBody = array_pop($parts);
414
        $responseHeader = array_pop($parts);
415
        $this->response->setHeaders($this->parseHeaders($responseHeader));
416
417
        curl_close($curlHandle);
418
419
        return $responseBody;
420
    }
421
422
    /**
423
     * Get the header info to store.
424
     *
425
     * @param string $header
426
     *
427
     * @return array
428
     */
429
    private function parseHeaders($header)
430
    {
431
        $headers = [];
432
        foreach (explode("\r\n", $header) as $line) {
433
            if (strpos($line, ':') !== false) {
434
                list ($key, $value) = explode(': ', $line);
435
                $key = str_replace('-', '_', strtolower($key));
436
                $headers[$key] = trim($value);
437
            }
438
        }
439
        return $headers;
440
    }
441
442
    /**
443
     * Encode application authorization header with base64.
444
     *
445
     * @param Consumer $consumer
446
     *
447
     * @return string
448
     */
449
    private function encodeAppAuthorization(Consumer $consumer)
450
    {
451
        $key = rawurlencode($consumer->key);
452
        $secret = rawurlencode($consumer->secret);
453
        return base64_encode($key . ':' . $secret);
454
    }
455
456
    /**
457
     * Is the code running from a Phar module.
458
     *
459
     * @return boolean
460
     */
461
    private function pharRunning()
462
    {
463
        return class_exists('Phar') && !empty(\Phar::running(false));
464
    }
465
}
466