Completed
Push — master ( 367b93...f210fc )
by Hector
01:52
created

TwitterAds::instance()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Hborras\TwitterAdsSDK;
4
5
use Exception;
6
use Hborras\TwitterAdsSDK\TwitterAds\Account;
7
use Hborras\TwitterAdsSDK;
8
use Hborras\TwitterAdsSDK\TwitterAds\Cursor;
9
use Hborras\TwitterAdsSDK\TwitterAds\Errors\BadRequest;
10
use Hborras\TwitterAdsSDK\TwitterAds\Errors\Forbidden;
11
use Hborras\TwitterAdsSDK\TwitterAds\Errors\NotAuthorized;
12
use Hborras\TwitterAdsSDK\TwitterAds\Errors\NotFound;
13
use Hborras\TwitterAdsSDK\TwitterAds\Errors\RateLimit;
14
use Hborras\TwitterAdsSDK\TwitterAds\Errors\ServerError;
15
use Hborras\TwitterAdsSDK\TwitterAds\Errors\ServiceUnavailable;
16
use Hborras\TwitterAdsSDK\Util\JsonDecoder;
17
18
/**
19
 * TwitterAds class for interacting with the Twitter API.
20
 *
21
 * @author Hector Borras <[email protected]>
22
 */
23
class TwitterAds extends Config
24
{
25
    const API_VERSION      = '1';
26
    const API_REST_VERSION = '1.1';
27
    const API_HOST         = 'https://ads-api.twitter.com';
28
    const API_HOST_SANDBOX = 'https://ads-api-sandbox.twitter.com';
29
    const API_HOST_OAUTH   = 'https://api.twitter.com';
30
    const UPLOAD_HOST      = 'https://upload.twitter.com';
31
    const UPLOAD_PATH      = 'media/upload.json';
32
    const UPLOAD_CHUNK     = 40960; // 1024 * 40
33
34
    /** @var TwitterAds */
35
    protected static $instance;
36
    /** @var  string Method used for the request */
37
    private $method;
38
    /** @var  string Resource used for the request */
39
    private $resource;
40
    /** @var Response details about the result of the last request */
41
    private $response;
42
    /** @var string|null Application bearer token */
43
    private $bearer;
44
    /** @var Consumer Twitter application details */
45
    private $consumer;
46
    /** @var Token|null User access token details */
47
    private $token;
48
    /** @var HmacSha1 OAuth 1 signature type used by Twitter */
49
    private $signatureMethod;
50
    /** @var  bool Sandbox allows to make requests thought sandbox environment */
51
    private $sandbox;
52
    /** @var string */
53
    private $accountId;
54
55
    /**
56
     * @return TwitterAds|null
57
     */
58
    public static function instance()
59
    {
60
        return static::$instance;
61
    }
62
63
    /**
64
     * @param TwitterAds $instance
65
     */
66
    public static function setInstance(TwitterAds $instance)
67
    {
68
        static::$instance = $instance;
69
    }
70
71
    /**
72
     * Constructor.
73
     *
74
     * @param string $consumerKey The Application Consumer Key
75
     * @param string $consumerSecret The Application Consumer Secret
76
     * @param string|null $oauthToken The Client Token
77
     * @param string|null $oauthTokenSecret The Client Token Secret
78
     * @param string $accountId
79
     * @param bool $sandbox The Sandbox environment (optional)
80
     */
81
    public function __construct($consumerKey, $consumerSecret, $oauthToken = '', $oauthTokenSecret = '', $accountId = '', $sandbox = false)
82
    {
83
        $this->resetLastResponse();
84
        $this->signatureMethod = new HmacSha1();
85
        $this->consumer = new Consumer($consumerKey, $consumerSecret);
86
        if (!empty($oauthToken) && !empty($oauthTokenSecret)) {
87
            $this->token = new Token($oauthToken, $oauthTokenSecret);
88
        }
89
        if (empty($oauthToken) && !empty($oauthTokenSecret)) {
90
            $this->bearer = $oauthTokenSecret;
91
        }
92
        $this->sandbox = $sandbox;
93
        $this->accountId = $accountId;
94
    }
95
96
    /**
97
     * @param $consumerKey
98
     * @param $consumerSecret
99
     * @param $oauthToken
100
     * @param $oauthTokenSecret
101
     * @param string $accountId
102
     * @param bool $sandbox
103
     * @return static
104
     */
105
    public static function init($consumerKey, $consumerSecret, $oauthToken = '', $oauthTokenSecret = '', $accountId = '', $sandbox = false)
106
    {
107
108
        $api = new static($consumerKey, $consumerSecret, $oauthToken, $oauthTokenSecret, $accountId, $sandbox);
109
        static::setInstance($api);
110
111
        return $api;
112
    }
113
114
    /**
115
     * @return Account|Cursor
116
     */
117
    public function getAccounts()
118
    {
119
        return (new Account($this))->all();
120
    }
121
122
    /**
123
     * @param string $oauthToken
124
     * @param string $oauthTokenSecret
125
     */
126
    public function setOauthToken($oauthToken, $oauthTokenSecret)
127
    {
128
        $this->token = new Token($oauthToken, $oauthTokenSecret);
129
    }
130
131
    /**
132
     * @return string|null
133
     */
134
    public function getLastApiPath()
135
    {
136
        return $this->response->getApiPath();
137
    }
138
139
    /**
140
     * @return int
141
     */
142
    public function getLastHttpCode()
143
    {
144
        return $this->response->getHttpCode();
145
    }
146
147
    /**
148
     * @return array
149
     */
150
    public function getLastXHeaders()
151
    {
152
        return $this->response->getXHeaders();
153
    }
154
155
    /**
156
     * @return array|object|null
157
     */
158
    public function getLastBody()
159
    {
160
        return $this->response->getBody();
161
    }
162
163
    /**
164
     * Resets the last response cache.
165
     */
166
    public function resetLastResponse()
167
    {
168
        $this->response = new Response();
169
    }
170
171
    /**
172
     * Make URLs for user browser navigation.
173
     *
174
     * @param string $path
175
     * @param array $parameters
176
     *
177
     * @return string
178
     */
179
    public function url($path, array $parameters)
180
    {
181
        $this->resetLastResponse();
182
        $this->response->setApiPath($path);
183
        $query = http_build_query($parameters);
184
185
        return sprintf('%s/%s?%s', self::API_HOST_OAUTH, $path, $query);
186
    }
187
188
    /**
189
     * Make /oauth/* requests to the API.
190
     *
191
     * @param string $path
192
     * @param array $parameters
193
     * @return array
194
     * @throws Exception
195
     */
196
    public function oauth($path, array $parameters = [])
197
    {
198
        $response = [];
199
        $this->resetLastResponse();
200
        $this->response->setApiPath($path);
201
        $url = sprintf('%s/%s', self::API_HOST_OAUTH, $path);
202
        $result = $this->oAuthRequest($url, 'POST', $parameters);
203
204
        if ($this->getLastHttpCode() != 200) {
205
            throw new TwitterAdsException($result, 500, null, $result);
206
        }
207
208
        parse_str($result, $response);
209
        $this->response->setBody($response);
210
211
        return $response;
212
    }
213
214
    /**
215
     * Make /oauth2/* requests to the API.
216
     *
217
     * @param string $path
218
     * @param array $parameters
219
     *
220
     * @return array|object
221
     */
222
    public function oauth2($path, array $parameters = [])
223
    {
224
        $method = 'POST';
225
        $this->resetLastResponse();
226
        $this->response->setApiPath($path);
227
        $url = sprintf('%s/%s', self::API_HOST_OAUTH, $path);
228
        $request = Request::fromConsumerAndToken($this->consumer, $this->token, $method, $url, $parameters);
229
        $authorization = 'Authorization: Basic ' . $this->encodeAppAuthorization($this->consumer);
230
        $result = $this->request($request->getNormalizedHttpUrl(), $method, $authorization, $parameters);
231
        $response = JsonDecoder::decode($result, $this->decodeJsonAsArray);
232
        $this->response->setBody($response);
233
234
        return $response;
235
    }
236
237
    public function verifyCredentials($parameters = [])
238
    {
239
        return $this->http('GET', self::API_HOST_OAUTH, 'account/verify_credentials', $parameters);
240
    }
241
242
    /**
243
     * Make GET requests to the API.
244
     *
245
     * @param string $path
246
     * @param array $parameters
247
     *
248
     * @return Response
249
     */
250
    public function get($path, array $parameters = [])
251
    {
252
        return $this->http('GET', !$this->sandbox ? self::API_HOST : self::API_HOST_SANDBOX, $path, $parameters);
253
    }
254
255
    /**
256
     * Make POST requests to the API.
257
     *
258
     * @param string $path
259
     * @param array $parameters
260
     *
261
     * @param array $headers
262
     * @return Response
263
     */
264
    public function post($path, array $parameters = [], array $headers = [])
265
    {
266
        return $this->http('POST', !$this->sandbox ? self::API_HOST : self::API_HOST_SANDBOX, $path, $parameters, $headers);
267
    }
268
269
    /**
270
     * Make DELETE requests to the API.
271
     *
272
     * @param string $path
273
     * @param array $parameters
274
     *
275
     * @return Response
276
     */
277
    public function delete($path, array $parameters = [])
278
    {
279
        return $this->http('DELETE', !$this->sandbox ? self::API_HOST : self::API_HOST_SANDBOX, $path, $parameters);
280
    }
281
282
    /**
283
     * Make PUT requests to the API.
284
     *
285
     * @param string $path
286
     * @param array $parameters
287
     *
288
     * @return Response
289
     */
290
    public function put($path, array $parameters = [], array $headers = [])
291
    {
292
        return $this->http('PUT', !$this->sandbox ? self::API_HOST : self::API_HOST_SANDBOX, $path, $parameters, $headers);
293
    }
294
295
    /**
296
     * Upload media to upload.twitter.com.
297
     *
298
     * @param array $parameters
299
     * @param bool $chunked
300
     *
301
     * @return array|object
302
     */
303
    public function upload(array $parameters = [], $chunked = false)
304
    {
305
        if ($chunked) {
306
            return $this->uploadMediaChunked(self::UPLOAD_PATH, $parameters);
307
        } else {
308
            return $this->uploadMediaNotChunked(self::UPLOAD_PATH, $parameters)->getBody();
309
        }
310
    }
311
312
    /**
313
     * Private method to upload media (not chunked) to upload.twitter.com.
314
     *
315
     * @param string $path
316
     * @param array $parameters
317
     *
318
     * @return array|object
319
     */
320
    private function uploadMediaNotChunked($path, $parameters)
321
    {
322
        $file = file_get_contents($parameters['media']);
323
        $base = base64_encode($file);
324
        $parameters['media'] = $base;
325
326
        return $this->http('POST', self::UPLOAD_HOST, $path, $parameters);
327
    }
328
329
    /**
330
     * Private method to upload media (chunked) to upload.twitter.com.
331
     *
332
     * @param string $path
333
     * @param array $parameters
334
     *
335
     * @return array|object
336
     */
337
    private function uploadMediaChunked($path, $parameters)
338
    {
339
        if ($parameters['media_type'] == 'video/mp4') {
340
            $parameters['media_category'] = "amplify_video";
341
        } elseif ($parameters['media_type'] == 'image/gif') {
342
            $parameters['media_category'] = 'tweet_gif';
343
        }
344
345
        // Init
346
        $init = $this->http(
347
            'POST',
348
            self::UPLOAD_HOST,
349
            $path,
350
            [
351
                'command' => 'INIT',
352
                'media_type' => $parameters['media_type'],
353
                'media_category' => $parameters['media_category'],
354
                'total_bytes' => filesize($parameters['media'])
355
            ]
356
        )->getBody();
357
358
        // Append
359
        $segment_index = 0;
360
        $media = fopen($parameters['media'], 'rb');
361
        while (!feof($media)) {
362
            $this->http(
0 ignored issues
show
Unused Code introduced by
The call to the method Hborras\TwitterAdsSDK\Response::getBody() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
363
                'POST',
364
                self::UPLOAD_HOST,
365
                $path,
366
                [
367
                    'command' => 'APPEND',
368
                    'media_id' => $init->media_id_string,
369
                    'segment_index' => $segment_index++,
370
                    'media_data' => base64_encode(fread($media, self::UPLOAD_CHUNK)),
371
                ]
372
            )->getBody();
373
        }
374
        fclose($media);
375
        // Finalize
376
        $finalize = $this->http(
377
            'POST',
378
            self::UPLOAD_HOST,
379
            $path,
380
            [
381
                'command' => 'FINALIZE',
382
                'media_id' => $init->media_id_string,
383
            ]
384
        )->getBody();
385
386
        while (isset($finalize->processing_info)) {
387
            if (isset($finalize->processing_info->check_after_secs)) {
388
                sleep($finalize->processing_info->check_after_secs);
389
                $data = array(
390
                    'command' => 'STATUS',
391
                    'media_id' => $finalize->media_id
392
                );
393
                $finalize = $this->http('GET', self::UPLOAD_HOST, $path, $data)->getBody();
394
            } else {
395
                if (isset($finalize->processing_info->state) && $finalize->processing_info->state == 'succeeded') {
396
                    break;
397
                }
398
            }
399
        }
400
401
        return $finalize;
402
    }
403
404
    /**
405
     * @param string $method
406
     * @param string $host
407
     * @param string $path
408
     * @param array $parameters
409
     * @param array $headers
410
     * @return Response
411
     * @throws BadRequest
412
     * @throws Forbidden
413
     * @throws NotAuthorized
414
     * @throws NotFound
415
     * @throws RateLimit
416
     * @throws ServerError
417
     * @throws ServiceUnavailable
418
     */
419
    private function http($method, $host, $path, array $parameters, $headers = [])
420
    {
421
        $this->method = $method;
422
        $this->resource = $path;
423
        $this->resetLastResponse();
424
        if (strpos($path, TONUpload::DEFAULT_DOMAIN) === 0) {
425
            $url = $path;
426
        } else {
427
            if ($host == self::UPLOAD_HOST) {
428
                $url = sprintf('%s/%s/%s', $host, self::API_REST_VERSION, $path);
429
            } else {
430
                $url = sprintf('%s/%s/%s', $host, self::API_VERSION, $path);
431
            }
432
        }
433
434
        $this->response->setApiPath($path);
435
        $result = $this->oAuthRequest($url, $method, $parameters, $headers);
436
        $response = JsonDecoder::decode($result, $this->decodeJsonAsArray);
437
        $this->response->setBody($response);
438
        if ($this->getLastHttpCode() > 399) {
439
            $this->manageErrors($response);
440
        }
441
        return $this->response;
442
    }
443
444
    /**
445
     * @param $response
446
     * @throws BadRequest
447
     * @throws Forbidden
448
     * @throws NotAuthorized
449
     * @throws NotFound
450
     * @throws RateLimit
451
     * @throws ServerError
452
     * @throws ServiceUnavailable
453
     */
454
    public function manageErrors($response)
455
    {
456
        switch ($this->getLastHttpCode()) {
457
            case 400:
458
                throw new BadRequest(TwitterAdsException::BAD_REQUEST, 400, null, $response->errors);
459
            case 401:
460
                throw new NotAuthorized(TwitterAdsException::NOT_AUTHORIZED, 401, null, $response->errors);
461
            case 403:
462
                throw new Forbidden(TwitterAdsException::FORBIDDEN, 403, null, $response->errors);
463
            case 404:
464
                throw new NotFound(TwitterAdsException::NOT_FOUND, 404, null, $response->errors);
465
            case 429:
466
                throw new RateLimit(TwitterAdsException::RATE_LIMIT, 429, null, $response->errors, $this->response->getsHeaders());
467
            case 500:
468
                throw new ServerError(TwitterAdsException::SERVER_ERROR, 500, null, $response->errors);
469
            case 503:
470
                throw new ServiceUnavailable(TwitterAdsException::SERVICE_UNAVAILABLE, 503, null, $response->errors, $this->response->getsHeaders());
471
            default:
472
                throw new ServerError(TwitterAdsException::SERVER_ERROR, 500, null, $response->errors);
473
        }
474
    }
475
476
    /**
477
     * Format and sign an OAuth / API request.
478
     *
479
     * @param string $url
480
     * @param string $method
481
     * @param array $parameters
482
     *
483
     * @param array $headers
484
     * @return string
485
     * @throws TwitterAdsException
486
     */
487
    private function oAuthRequest($url, $method, array $parameters, $headers = [])
488
    {
489
        $request = Request::fromConsumerAndToken($this->consumer, $this->token, $method, $url, $parameters);
490
        if (array_key_exists('oauth_callback', $parameters)) {
491
            // Twitter doesn't like oauth_callback as a parameter.
492
            unset($parameters['oauth_callback']);
493
        }
494
        if ($this->bearer === null) {
495
            $request->signRequest($this->signatureMethod, $this->consumer, $this->token);
496
            $authorization = $request->toHeader();
497
        } else {
498
            $authorization = 'Authorization: Bearer ' . $this->bearer;
499
        }
500
        if (strpos($url, TONUpload::DEFAULT_DOMAIN) === 0) {
501
            return $this->request($url, $method, $authorization, $parameters, $headers);
502
        } else {
503
            return $this->request($request->getNormalizedHttpUrl(), $method, $authorization, $parameters, $headers);
504
        }
505
506
    }
507
508
    /**
509
     * Make an HTTP request.
510
     *
511
     * @param string $url
512
     * @param string $method
513
     * @param string $authorization
514
     * @param array $postfields
515
     *
516
     * @param array $headers
517
     * @return string
518
     * @throws TwitterAdsException
519
     */
520
    private function request($url, $method, $authorization, $postfields, $headers = [])
521
    {
522
        /* Curl settings */
523
        $options = [
524
            CURLOPT_VERBOSE => false,
525
            CURLOPT_CAINFO => __DIR__ . DIRECTORY_SEPARATOR . 'cacert.pem',
526
            CURLOPT_CONNECTTIMEOUT => $this->connectionTimeout,
527
            CURLOPT_HEADER => true,
528
            CURLOPT_HTTPHEADER => array_merge(['Accept: */*', $authorization, 'Expect:'], $headers, ['Connection: close']),
529
            CURLOPT_RETURNTRANSFER => true,
530
            CURLOPT_SSL_VERIFYHOST => 2,
531
            CURLOPT_SSL_VERIFYPEER => true,
532
            CURLOPT_TIMEOUT => $this->timeout,
533
            CURLOPT_URL => $url,
534
            CURLOPT_USERAGENT => $this->userAgent,
535
            CURLOPT_ENCODING => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
536
        ];
537
538
        if (!empty($this->proxy)) {
539
            $options[CURLOPT_PROXY] = $this->proxy['CURLOPT_PROXY'];
540
            $options[CURLOPT_PROXYUSERPWD] = $this->proxy['CURLOPT_PROXYUSERPWD'];
541
            $options[CURLOPT_PROXYPORT] = $this->proxy['CURLOPT_PROXYPORT'];
542
            $options[CURLOPT_PROXYAUTH] = CURLAUTH_BASIC;
543
            $options[CURLOPT_PROXYTYPE] = CURLPROXY_HTTP;
544
        }
545
546
        switch ($method) {
547
            case 'GET':
548
                break;
549
            case 'POST':
550
                $options[CURLOPT_POST] = true;
551
                if (isset($postfields['raw'])) {
552
                    $options[CURLOPT_POSTFIELDS] = $postfields['raw'];
553
                } else {
554
                    $options[CURLOPT_POSTFIELDS] = Util::buildHttpQuery($postfields);
555
                }
556
557
                break;
558
            case 'DELETE':
559
                $options[CURLOPT_CUSTOMREQUEST] = 'DELETE';
560
                break;
561
            case 'PUT':
562
                $options[CURLOPT_CUSTOMREQUEST] = 'PUT';
563
                if (isset($postfields['raw'])) {
564
                    $options[CURLOPT_POSTFIELDS] = $postfields['raw'];
565
                }
566
                break;
567
        }
568
569
        if (in_array($method, ['GET', 'PUT', 'DELETE']) && !empty($postfields) && !isset($postfields['raw'])) {
570
            $options[CURLOPT_URL] .= '?' . Util::buildHttpQuery($postfields);
571
        }
572
573
        $curlHandle = curl_init();
574
        curl_setopt_array($curlHandle, $options);
575
        $response = curl_exec($curlHandle);
576
        // Throw exceptions on cURL errors.
577
        if (curl_errno($curlHandle) > 0) {
578
            throw new TwitterAdsException(curl_error($curlHandle), curl_errno($curlHandle), null, null);
579
        }
580
        $this->response->setHttpCode(curl_getinfo($curlHandle, CURLINFO_HTTP_CODE));
581
        $parts = explode("\r\n\r\n", $response);
582
        $responseBody = array_pop($parts);
583
        $responseHeader = array_pop($parts);
584
        $this->response->setHeaders($this->parseHeaders($responseHeader));
585
        curl_close($curlHandle);
586
        return $responseBody;
587
    }
588
589
    /**
590
     * Get the header info to store.
591
     *
592
     * @param string $header
593
     *
594
     * @return array
595
     */
596
    private function parseHeaders($header)
597
    {
598
        $headers = [];
599
        foreach (explode("\r\n", $header) as $line) {
600
            if (strpos($line, ':') !== false) {
601
                list($key, $value) = explode(': ', $line);
602
                $key = str_replace('-', '_', strtolower($key));
603
                $headers[$key] = trim($value);
604
            }
605
        }
606
607
        return $headers;
608
    }
609
610
    /**
611
     * Set API URLS.
612
     */
613
    public function accessTokenURL()
614
    {
615
        return 'https://api.twitter.com/oauth/access_token';
616
    }
617
618
    public function authenticateURL()
619
    {
620
        return 'https://api.twitter.com/oauth/authenticate';
621
    }
622
623
    public function authorizeURL()
624
    {
625
        return 'https://api.twitter.com/oauth/authorize';
626
    }
627
628
    public function requestTokenURL()
629
    {
630
        return 'https://api.twitter.com/oauth/request_token';
631
    }
632
633
    /**
634
     * Encode application authorization header with base64.
635
     *
636
     * @param Consumer $consumer
637
     *
638
     * @return string
639
     */
640
    private function encodeAppAuthorization($consumer)
641
    {
642
        // TODO: key and secret should be rfc 1738 encoded
643
        $key = $consumer->key;
644
        $secret = $consumer->secret;
645
646
        return base64_encode($key . ':' . $secret);
647
    }
648
649
    /**
650
     * Return current response. Allows inheritance.
651
     *
652
     * @return Response
653
     */
654
    public function getResponse()
655
    {
656
        return $this->response;
657
    }
658
659
    /**
660
     * @return string
661
     */
662
    public function getMethod()
663
    {
664
        return $this->method;
665
    }
666
667
    /**
668
     * @return string
669
     */
670
    public function getResource()
671
    {
672
        return $this->resource;
673
    }
674
675
    /**
676
     * @return string
677
     */
678
    public function getAccountId()
679
    {
680
        return $this->accountId;
681
    }
682
683
    /**
684
     * @param string $accountId
685
     */
686
    public function setAccountId($accountId)
687
    {
688
        $this->accountId = $accountId;
689
    }
690
691 View Code Duplication
    public function getRequestToken($oauth_callback)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
692
    {
693
        $parameters = array();
694
        $parameters['oauth_callback'] = $oauth_callback;
695
        $request = $this->oAuthRequest($this->requestTokenURL(), 'GET', $parameters);
696
        $token = self::parse_parameters($request);
697
698
        return $token;
699
    }
700
701
    /**
702
     * Exchange request token and secret for an access token and
703
     * secret, to sign API calls.
704
     *
705
     * @param $oauth_verifier
706
     * @return array ("oauth_token" => "the-access-token",
707
     *                "oauth_token_secret" => "the-access-secret",
708
     * "user_id" => "9436992",
709
     * "screen_name" => "abraham")
710
     */
711 View Code Duplication
    public function getAccessToken($oauth_verifier)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
712
    {
713
        $parameters = array();
714
        $parameters['oauth_verifier'] = $oauth_verifier;
715
        $request = $this->oAuthRequest($this->accessTokenURL(), 'GET', $parameters);
716
        $token = self::parse_parameters($request);
717
718
        return $token;
719
    }
720
721
    // This function takes a input like a=b&a=c&d=e and returns the parsed
722
    // parameters like this
723
    // array('a' => array('b','c'), 'd' => 'e')
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
724 View Code Duplication
    public static function parse_parameters($input)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
725
    {
726
        if (!isset($input) || !$input) {
727
            return array();
728
        }
729
730
        $pairs = explode('&', $input);
731
732
        $parsed_parameters = array();
733
        foreach ($pairs as $pair) {
734
            $split = explode('=', $pair, 2);
735
            $parameter = self::urldecode_rfc3986($split[0]);
736
            $value = isset($split[1]) ? self::urldecode_rfc3986($split[1]) : '';
737
738
            if (isset($parsed_parameters[$parameter])) {
739
                // We have already recieved parameter(s) with this name, so add to the list
740
                // of parameters with this name
741
742
                if (is_scalar($parsed_parameters[$parameter])) {
743
                    // This is the first duplicate, so transform scalar (string) into an array
744
                    // so we can add the duplicates
745
                    $parsed_parameters[$parameter] = array($parsed_parameters[$parameter]);
746
                }
747
748
                $parsed_parameters[$parameter][] = $value;
749
            } else {
750
                $parsed_parameters[$parameter] = $value;
751
            }
752
        }
753
754
        return $parsed_parameters;
755
    }
756
757
    public static function urlencode_rfc3986($input)
758
    {
759
        if (is_array($input)) {
760
            return array_map(array(__CLASS__, 'urlencode_rfc3986'), $input);
761
        } elseif (is_scalar($input)) {
762
            return str_replace(
763
                '',
764
                ' ',
765
                str_replace('%7E', '~', rawurlencode($input))
766
            );
767
        } else {
768
            return '';
769
        }
770
    }
771
772
    // This decode function isn't taking into consideration the above
773
    // modifications to the encoding process. However, this method doesn't
774
    // seem to be used anywhere so leaving it as is.
775
    public static function urldecode_rfc3986($string)
776
    {
777
        return urldecode($string);
778
    }
779
780
    /**
781
     * Get the authorize URL.
782
     *
783
     * @param $token
784
     * @param bool $sign_in_with_twitter
785
     * @return string
786
     */
787
    public function getAuthorizeURL($token, $sign_in_with_twitter = true)
788
    {
789
        if (is_array($token)) {
790
            $token = $token['oauth_token'];
791
        }
792
        if (empty($sign_in_with_twitter)) {
793
            return $this->authorizeURL() . "?oauth_token={$token}";
794
        } else {
795
            return $this->authenticateURL() . "?oauth_token={$token}";
796
        }
797
    }
798
}
799