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.
Test Failed
Push — master ( 4481ca...5e00e9 )
by sunsky
10:52
created

Request::options()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
rs 10
ccs 0
cts 0
cp 0
cc 1
eloc 2
nc 1
nop 2
crap 2
1
<?php
2
/**
3
 *
4
 * @author  [email protected] [email protected]
5
 * Date: 2017/6/16
6
 * Time: 10:02
7
 * @version $Id: $
8
 * @since 1.0
9
 * @copyright Sina Corp.
10
 */
11
12
namespace MultiHttp;
13
14
use MultiHttp\Exception\InvalidArgumentException;
15
use MultiHttp\Exception\InvalidOperationException;
16
17
/**
18
 * Class Request
19
 * @package MultiHttp
20
 */
21
class Request extends Http
22
{
23
    /**
24
     * you can implement more traits
25
     */
26
    use JsonTrait;
27
    /**
28
     *
29
     */
30
    const MAX_REDIRECTS_DEFAULT = 10;
31
    protected static $curlAlias = array(
32
        'url' => 'CURLOPT_URL',
33
        'uri' => 'CURLOPT_URL',
34
        'debug' => 'CURLOPT_VERBOSE',//for debug verbose
35
        'method' => 'CURLOPT_CUSTOMREQUEST',
36
        'data' => 'CURLOPT_POSTFIELDS', // array or string , file begin with '@'
37
        'ua' => 'CURLOPT_USERAGENT',
38
        'timeout' => 'CURLOPT_TIMEOUT', // (secs) 0 means indefinitely
39
        'connect_timeout' => 'CURLOPT_CONNECTTIMEOUT',
40
        'referer' => 'CURLOPT_REFERER',
41
        'binary' => 'CURLOPT_BINARYTRANSFER',
42
        'port' => 'CURLOPT_PORT',
43
        'header' => 'CURLOPT_HEADER', // TRUE:include header
44
        'headers' => 'CURLOPT_HTTPHEADER', // array
45
        'download' => 'CURLOPT_FILE', // writing file stream (using fopen()), default is STDOUT
46
        'upload' => 'CURLOPT_INFILE', // reading file stream
47
        'transfer' => 'CURLOPT_RETURNTRANSFER', // TRUE:return string; FALSE:output directly (curl_exec)
48
        'follow_location' => 'CURLOPT_FOLLOWLOCATION',
49 2
        'timeout_ms' => 'CURLOPT_TIMEOUT_MS', // milliseconds,  libcurl version > 7.36.0 ,
50
        /**
51 2
         * private properties
52
         */
53 2
        'expectsMime' => null, //expected mime
54 2
        'sendMime' => null, //send mime
55
        'ip' => null,//specify ip to send request
56
        'callback' => null,//callback on end
57 1
58 1
    );
59
    protected static $loggerHandler;
60
    public
61 2
        $curlHandle,
0 ignored issues
show
Coding Style introduced by
It is generally advisable to only define one property per statement.

Only declaring a single property per statement allows you to later on add doc comments more easily.

It is also recommended by PSR2, so it is a common style that many people expect.

Loading history...
Coding Style introduced by
The visibility should be declared for property $curlHandle.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
62 2
        $uri,
63
        $sendMime,
64
        $expectedMime;
65 2
    protected $options = array(
66 2
        'CURLOPT_MAXREDIRS' => 10,
67
        'CURLOPT_SSL_VERIFYPEER' => false,//for https
68
        'CURLOPT_SSL_VERIFYHOST' => 0,//for https
69 2
        'CURLOPT_IPRESOLVE' => CURL_IPRESOLVE_V4,//ipv4 first
70 2
        'header' => true,
71
        'method' => self::GET,
72
        'transfer' => true,
73 2
        'headers' => array(),
74 2
        'follow_location' => true,
75
        'timeout' => 0);
76
    protected $endCallback;
77
    protected $withURIQuery;
78
    protected $hasInitialized = false;
79
80
    /**
81 2
     * Request constructor.
82
     */
83
    protected function __construct()
84 2
    {
85 2
    }
86
87
    /**
88 2
     * @return Request
89
     */
90
    public static function create()
91
    {
92
        return new self;
93
    }
94
95 1
    /**
96 1
     * @param callable $handler
97 1
     */
98 1
    public static function setLogHandler(callable $handler)
99 1
    {
100 1
        self::$loggerHandler = $handler;
101
    }
102
103
    /**
104
     * @param $parsedComponents
105 1
     * @return string
106
     */
107
    private static function combineUrl($parsedComponents)
108 1
    {
109 1
        $scheme = isset($parsedComponents['scheme']) ? $parsedComponents['scheme'] . '://' : '';
110
        $host = isset($parsedComponents['host']) ? $parsedComponents['host'] : '';
111
        $port = isset($parsedComponents['port']) ? ':' . $parsedComponents['port'] : '';
112 2
        $user = isset($parsedComponents['user']) ? $parsedComponents['user'] : '';
113 2
        $pass = isset($parsedComponents['pass']) ? ':' . $parsedComponents['pass'] : '';
114 2
        $pass = ($user || $pass) ? "$pass@" : '';
115
        $path = isset($parsedComponents['path']) ? $parsedComponents['path'] : '';
116 2
        $query = isset($parsedComponents['query']) ? '?' . $parsedComponents['query'] : '';
117
        $fragment = isset($parsedComponents['fragment']) ? '#' . $parsedComponents['fragment'] : '';
118
        return "$scheme$user$pass$host$port$path$query$fragment";
119 2
    }
120 2
121 2
    /**
122
     * @param string $mime
123
     * @return $this
124 2
     */
125 2
    public function expectsMime($mime = 'json')
126
    {
127 2
        $this->expectedMime = $mime;
128 1
        return $this;
129 1
    }
130
131 2
    /**
132 2
     * @param string $mime
133 2
     * @return Request
134
     */
135
    public function sendMime($mime = 'json')
136 2
    {
137
        $this->sendMime = $mime;
138
        $this->addHeader('Content-type', Mime::getFullMime($mime));
139
        return $this;
140
    }
141
142
    /**
143
     * @param $headerName
144
     * @param $value , can be rawurlencode
145
     * @return $this
146
     */
147
    public function addHeader($headerName, $value)
148
    {
149 1
        $this->options['headers'][] = $headerName . ': ' . $value;
150 1
        return $this;
151
    }
152
153 1
    /**
154 1
     * @param $uri
155
     * @return $this
156
     */
157
    public function uri($uri)
158
    {
159
        $this->uri = $uri;
160
        return $this;
161
    }
162
163
    /**
164
     * @param $timeout seconds, can be float
165 2
     * @return $this
166 2
     */
167
    public function timeout($timeout)
168
    {
169
        $this->options['timeout'] = $timeout;
170
        return $this;
171
    }
172 1
173 1
    /**
174 1
     * @param array $headers
175 1
     * @return $this
176 1
     */
177 1
    public function addHeaders(array $headers)
178
    {
179 1
        foreach ($headers as $header => $value) {
180
            $this->addHeader($header, $value);
181
        }
182 2
        return $this;
183 2
    }
184 2
185 2
    /**
186 2
     * @return mixed
187
     */
188
    public function endCallback()
189 2
    {
190
        return $this->endCallback;
191 2
    }
192 1
193 1
    /**
194 1
     * @return bool
195 1
     */
196 1
    public function hasEndCallback()
197
    {
198
        return isset($this->endCallback);
199
    }
200 1
201 1
    /**
202 1
     * @param $field alias or field name
203
     * @return bool|mixed
204
     */
205 2
    public function getIni($field = null)
206
    {
207
        if(!$field) return $this->options;
208
        $full = self::fullOption($field);
209
        return isset($this->options[$full]) ? $this->options[$full] : false;
210
    }
211
212
    /**
213
     * @param $key
214
     * @return mixed
215 2
     */
216 2
    protected static function fullOption($key)
217 2
    {
218
        $full = false;
219 1
        if (isset(self::$curlAlias[$key])) {
220
            $full = self::$curlAlias[$key];
221
        } elseif ((substr($key, 0, strlen('CURLOPT_')) == 'CURLOPT_') && defined($key)) {
222
            $full = $key;
223 2
        }
224 2
        return $full;
225
    }
226 2
227
    /**
228
     * @param $data
229 2
     * @return $this
230
     */
231
    public function addQuery($data)
232 2
    {
233 2
        if (!empty($data)) {
234 2
            if (is_array($data)) {
235 2
                $this->withURIQuery = http_build_query($data);
236 2
            } else if (is_string($data)) {
237 2
                $this->withURIQuery = $data;
238
            } else {
239
                throw new InvalidArgumentException('data must be array or string');
240 2
            }
241 2
        }
242
        return $this;
243
    }
244
245
    /**
246
     * @param $uri
247 2
     * @param null $payload
248 2
     * @param array $options
249 2
     * @return Request
250 2
     */
251 2
    public function post($uri, $payload = null, array $options = array())
252 2
    {
253
        return $this->ini(Http::POST, $uri, $payload, $options);
254 2
    }
255
256 2
    /**
257 2
     * @param $method
258 2
     * @param $url
259 2
     * @param $data
260 2
     * @param array $options
261 2
     * @return $this
262 2
     */
263 View Code Duplication
    protected function ini($method, $url, $data, array $options = array())
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...
264
    {
265
        $options = array('url' => $url, 'method' => $method, 'data' => $data) + $options;
266
        $this->addOptions($options);
267
268
        return $this;
269
    }
270
271
    /**
272
     * @param array $options
273
     * @return $this
274
     */
275
    public function addOptions(array $options = array())
276
    {
277
        $this->options = $options + $this->options;
278
        $this->uri = $this->options['url'];
279
        return $this;
280
    }
281
282
    /**
283
     * @param $uri
284
     * @param null $payload
285
     * @param array $options
286
     * @return Request
287
     */
288
    function put($uri, $payload = null, array $options = array())
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
289
    {
290
        return $this->ini(Http::PUT, $uri, $payload, $options);
291
    }
292
293
    /**
294
     * @param $uri
295
     * @param null $payload
296
     * @param array $options
297
     * @return Request
298
     */
299
    function patch($uri, $payload = null, array $options = array())
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
300
    {
301
        return $this->ini(Http::PATCH, $uri, $payload, $options);
302
    }
303
304
    /**
305
     * @param $uri
306
     * @param array $options
307
     * @return Request
308
     */
309
    public function get($uri, array $options = array())
310
    {
311
        return $this->ini(Http::GET, $uri, array(), $options);
312
    }
313
314
    /**
315
     * @param $uri
316
     * @param array $options
317
     * @return Request
318
     */
319
    function options($uri, array $options = array())
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
320
    {
321
        return $this->ini(Http::OPTIONS, $uri, array(), $options);
322
    }
323
324
    /**
325
     * @param $uri
326
     * @param array $options
327
     * @return Request
328
     */
329
    function head($uri, array $options = array())
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
330
    {
331
        return $this->ini(Http::HEAD, $uri, array('CURLOPT_NOBODY' => true), $options);
332
    }
333
334
    /**
335
     * @param $uri
336
     * @param array $options
337
     * @return Request
338
     */
339
    function delete($uri, array $options = array())
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
340
    {
341
        return $this->ini(Http::DELETE, $uri, array(), $options);
342
    }
343
344
    /**
345
     * @param $uri
346
     * @param array $options
347
     * @return Request
348
     */
349
    function trace($uri, array $options = array())
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
350
    {
351
        return $this->ini(Http::TRACE, $uri, array(), $options);
352
    }
353
354
    /**
355
     * @param bool $isMultiCurl
356
     * @return Response
357
     */
358
    public function send($isMultiCurl = false)
359
    {
360
        try {
361
            if (!$this->hasInitialized)
362
                $this->applyOptions();
363
            $response = $this->makeResponse($isMultiCurl);
364
            $response->parse();
365
        } catch (\Exception $e) {
366
            if(!isset($response)) $response = Response::create($this, null, null, null, null);
367
            $response->error = $e->getMessage();
368
            $response->errorCode = 999;
369
        }
370
371
        if (self::$loggerHandler) {
372
            call_user_func(self::$loggerHandler, $response);
373
        }
374
        if ($this->endCallback) {
375
            call_user_func($this->endCallback, $response);
376
        }
377
378
        return $response;
379
    }
380
381
    /**
382
     * @return $this
383
     */
384
    public function applyOptions()
385
    {
386
        $curl = curl_init();
387
        $this->curlHandle = $curl;
388
        $this->prepare();
389
        $this->hasInitialized = true;
390
        return $this;
391
    }
392
393
    /**
394
     * @return $this
395
     */
396
    protected function prepare()
397
    {
398
        $this->options['url'] = trim($this->options['url']);
399
        if (empty($this->options['url'])) {
400
            throw new InvalidArgumentException('url can not empty');
401
        }
402
403
        if(isset($this->options['expectsMime'])){
404
            $this->expectsMime($this->options['expectsMime']);
405
//            unset($this->options['expectsMime']);
0 ignored issues
show
Unused Code Comprehensibility introduced by
82% 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...
406
        }
407
408
        if(isset($this->options['sendMime'])){
409
            $this->sendMime($this->options['sendMime']);
410
//            unset($this->options['sendMime']);
0 ignored issues
show
Unused Code Comprehensibility introduced by
82% 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...
411
        }
412
413
        $this->serializeBody();
414
415
        //try fix url
416
        if (strpos($this->options['url'], '://') === FALSE) $this->options['url'] = 'http://' . $this->options['url'];
417
        $components = parse_url($this->options['url']);
418
        if(FALSE === $components) throw new InvalidArgumentException('formatting url occurs error: '. $this->options['url']);
419
        if($this->withURIQuery){
420
            if(isset($components['query'])) $components['query'] .= '&'. trim($this->withURIQuery);
421
            else $components['query'] = trim($this->withURIQuery);
422
        }
423
        $this->options['url'] = self::combineUrl($components);
424
425
        if (isset($this->options['callback'])) {
426
            $this->onEnd($this->options['callback']);
427
//            unset($this->options['callback']);
0 ignored issues
show
Unused Code Comprehensibility introduced by
82% 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...
428
        }
429
        //swap ip and host
430
        if (!empty($this->options['ip'])) {
431
            $matches = array();
432
            preg_match('/\/\/([^\/]+)/', $this->options['url'], $matches);
433
            $host = $matches[1];
434
            if (empty($this->options['headers']) || !is_array($this->options['headers'])) {
435
                $this->options['headers'] = array('Host: ' . $host);
436
            } else {
437
                $this->options['headers'][] = 'Host: ' . $host;
438
            }
439
            $this->options['url'] = preg_replace('/\/\/([^\/]+)/', '//' . $this->options['ip'], $this->options['url']);
440
//            unset($this->options['ip']);
0 ignored issues
show
Unused Code Comprehensibility introduced by
82% 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...
441
            unset($host);
442
        }
443
        //process version
444
        if (!empty($this->options['http_version'])) {
445
            $version = $this->options['http_version'];
446
            if ($version == '1.0') {
447
                $this->options['CURLOPT_HTTP_VERSION'] = CURLOPT_HTTP_VERSION_1_0;
448
            } elseif ($version == '1.1') {
449
                $this->options['CURLOPT_HTTP_VERSION'] = CURLOPT_HTTP_VERSION_1_1;
450
            }
451
452
            unset($version);
453
        }
454
455
        //convert secs to milliseconds
456
        if (defined('CURLOPT_TIMEOUT_MS')) {
457
            if (!isset($this->options['timeout_ms'])) {
458
                $this->options['timeout_ms'] = intval($this->options['timeout'] * 1000);
459
            } else {
460
                $this->options['timeout_ms'] = intval($this->options['timeout_ms']);
461
            }
462
        }
463
464
465
        $cURLOptions = self::filterAndRaw($this->options);
466
        curl_setopt_array($this->curlHandle, $cURLOptions);
467
468
        return $this;
469
    }
470
471
    public function serializeBody()
472
    {
473
        if (isset($this->options['data'])) {
474
            if (isset($this->sendMime)) {
475
                $method = $this->sendMime;
476
                if (!method_exists($this, $method)) throw new InvalidOperationException($method . ' is not exists in ' . __CLASS__);
477
                $this->options['data'] = $this->$method($this->options['data']);
478
            } else {
479
                $this->options['data'] = is_array($this->options['data']) ? http_build_query($this->options['data']) : $this->options['data'];//for better compatibility
480
            }
481
        }
482
    }
483
484
    /**
485
     * @param callable $callback
486
     * @return $this
487
     */
488
    public function onEnd(callable $callback)
489
    {
490
        if (!is_callable($callback)) {
491
            throw new InvalidArgumentException('callback not is callable :' . print_r($callback, 1));
492
        }
493
494
        $this->endCallback = $callback;
495
        return $this;
496
    }
497
498
    /**
499
     * @param array $options
500
     * @return array
501
     */
502
    protected static function filterAndRaw(array &$options)
503
    {
504
        $opts = $fullsOpts = array();
505
        foreach ($options as $key => $val) {
506
            $fullOption = self::fullOption($key);
507
508
            if ($fullOption) {
509
                $fullsOpts[$fullOption] = $val;
510
                $opts[constant($fullOption)] = $val;
511
            }
512
            unset($options[$key]);
513
        }
514
        $options = $fullsOpts;
515
        return $opts;
516
    }
517
518
    /**
519
     * @param bool $isMultiCurl
520
     * @return Response
521
     * @throws \Exception
522
     */
523
    public function makeResponse($isMultiCurl = false)
524
    {
525
        $body = $isMultiCurl ? curl_multi_getcontent($this->curlHandle) : curl_exec($this->curlHandle);
526
        $info = curl_getinfo($this->curlHandle);
527
        $errorCode = curl_errno($this->curlHandle);
528
        $error = curl_error($this->curlHandle);
529
        $response = Response::create($this, $body, $info, $errorCode, $error);
530
        return $response;
531
    }
532
533
534
}
535