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 ( 48806f...49d06b )
by sunsky
02:11
created

Request::quickGet()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 0
cts 0
cp 0
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 3
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
16
class Request extends Http
17
{
18
    const MAX_REDIRECTS_DEFAULT = 10;
19
    protected static $curlAlias = array(
20
        'url' => 'CURLOPT_URL',
21
        'uri' => 'CURLOPT_URL',
22
        'debug' => 'CURLOPT_VERBOSE',//for debug verbose
23
        'method' => 'CURLOPT_CUSTOMREQUEST',
24
        'data' => 'CURLOPT_POSTFIELDS', // array or string , file begin with '@'
25
        'ua' => 'CURLOPT_USERAGENT',
26
        'timeout' => 'CURLOPT_TIMEOUT', // (secs) 0 means indefinitely
27
        'connect_timeout' => 'CURLOPT_CONNECTTIMEOUT',
28
        'referer' => 'CURLOPT_REFERER',
29
        'binary' => 'CURLOPT_BINARYTRANSFER',
30
        'port' => 'CURLOPT_PORT',
31
        'header' => 'CURLOPT_HEADER', // TRUE:include header
32
        'headers' => 'CURLOPT_HTTPHEADER', // array
33
        'download' => 'CURLOPT_FILE', // writing file stream (using fopen()), default is STDOUT
34
        'upload' => 'CURLOPT_INFILE', // reading file stream
35
        'transfer' => 'CURLOPT_RETURNTRANSFER', // TRUE:return string; FALSE:output directly (curl_exec)
36
        'follow_location' => 'CURLOPT_FOLLOWLOCATION',
37
        'timeout_ms' => 'CURLOPT_TIMEOUT_MS', // milliseconds,  libcurl version > 7.36.0 ,
38
    );
39
    protected static $logger;
40
    public $curlHandle;
41
    public
42
        $uri,
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 $uri.

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...
43
        $timeout,
44
        $maxRedirects,
45
        $followRedirects;
46
    public $cert;
47
    public $key;
48
    public $passphrase;
49
    public $encoding;
50
    public $payload;
51
    public $retryTimes;
52
53
    /**
54
     * @var int seconds
55
     */
56
    public $retryDuration;
57
    protected $options = array(
58
        'CURLOPT_MAXREDIRS' => 10,
59
        'header' => true,
60
        'method' => self::GET,
61
        'transfer' => true,
62
        'follow_location' => true,
63
        'timeout' => 0,
64
//        'ip' => null, //host, in string, .e.g: 172.16.1.1:888
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% 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...
65
        'retry_times' => 1,//redo task when failed
66
        'retry_duration' => 0,//in seconds
67
    );
68
    protected $endCallback;
69
    protected $withURIQuery;
70
    protected $hasInitialized = false;
71
72
    protected function __construct()
73
    {
74
75
    }
76
77
    public static function create()
78
    {
79
        return new self;
80
    }
81
82
    public static function setLogger($logger)
83 2
    {
84
        self::$logger = $logger;
85 2
    }
86
87
    /**
88
     * Specify   timeout
89
     * @param float|int $timeout seconds to timeout the HTTP call
90 2
     * @return Request
91
     */
92 2
    public function timeout($timeout)
93
    {
94
        $this->timeout = $timeout;
95
        return $this;
96
    }
97
98 1
    public function noFollow()
99
    {
100 1
        return $this->follow(0);
101 1
    }
102
103
    /**
104
     * If the response is a 301 or 302 redirect, automatically
105
     * send off another request to that location
106
     * @param int $follow follow or not to follow or maximal number of redirects
107 2
     * @return Request
108
     */
109 2
    public function follow($follow)
110 2
    {
111 2
        $this->maxRedirects = abs($follow);
112 2
        $this->followRedirects = $follow > 0;
113 2
        return $this;
114 2
    }
115 2
116 2
    public function endCallback()
117 2
    {
118 2
        return $this->endCallback;
119
    }
120
121
    public function hasEndCallback()
122
    {
123
        return isset($this->endCallback);
124
    }
125 2
126
    public function uri($uri)
127 2
    {
128 2
        $this->uri = $uri;
129
        return $this;
130
    }
131
132
    public function hasCert()
133
    {
134
        return isset($this->cert) && isset($this->key);
135 2
    }
136
137 2
    /**
138 2
     * Use Client Side Cert Authentication
139 2
     * @param string $key file path to client key
140
     * @param string $cert file path to client cert
141
     * @param string $passphrase for client key
142
     * @param string $encoding default PEM
143
     * @return Request
144
     */
145
    public function cert($cert, $key, $passphrase = null, $encoding = 'PEM')
146
    {
147 2
        $this->cert = $cert;
148
        $this->key = $key;
149 2
        $this->passphrase = $passphrase;
150 2
        $this->encoding = $encoding;
151
        return $this;
152
    }
153
154
    public function body($payload, $mimeType = null)
155
    {
156
        $this->mime($mimeType);
157
        $this->payload = $payload;
158
        // Iserntentially don't call _serializePayload yet.  Wait until
159
        // we actually send off the request to convert payload to string.
160
        // At that time, the `serialized_payload` is set accordingly.
161
        return $this;
162
    }
163
    public function mime($mime)
164
    {
165
        if (empty($mime)) return $this;
166
        $this->content_type = $this->expected_type = Mime::getFullMime($mime);
0 ignored issues
show
Bug introduced by
The property content_type does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
Bug introduced by
The property expected_type does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
167
        if ($this->isUpload()) {
0 ignored issues
show
Bug introduced by
The method isUpload() does not seem to exist on object<MultiHttp\Request>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
168
            $this->neverSerializePayload();
0 ignored issues
show
Bug introduced by
The method neverSerializePayload() does not seem to exist on object<MultiHttp\Request>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
169
        }
170
        return $this;
171
    }
172
    public function addHeader($header_name, $value)
173
    {
174
        $this->headers[$header_name] = $value;
0 ignored issues
show
Bug introduced by
The property headers does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
175
        return $this;
176
    }
177 1
178
    public function addHeaders(array $headers)
179 1
    {
180 1
        foreach ($headers as $header => $value) {
181 1
            $this->addHeader($header, $value);
182 1
        }
183
        return $this;
184
    }
185
    public function expectsType($mime)
186
    {
187
        return $this->expects($mime);
188
    }
189
    public function sendType($mime)
190
    {
191
        return $this->contentType = $mime;
0 ignored issues
show
Bug introduced by
The property contentType does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
192
    }
193
    public function expects($mime)
194
    {
195
        if (empty($mime)) return $this;
196 2
        $this->expected_type = Mime::getFullMime($mime);
197
        return $this;
198 2
    }
199
    /**
200
     * @param $field alias or field name
201
     * @return bool|mixed
202
     */
203
    public function getIni($field)
204
    {
205 2
        $alias = self::optionAlias($field);
206
        return isset($this->options[$alias]) ? $this->options[$alias] : false;
207 2
    }
208 2
209 2
    /**
210
     * @param $key
211
     * @return mixed
212
     */
213
    protected static function optionAlias($key)
214
    {
215
        $alias = false;
216 2
        if (isset(self::$curlAlias[$key])) {
217
            $alias = self::$curlAlias[$key];
218 2
        } elseif ((substr($key, 0, strlen('CURLOPT_')) == 'CURLOPT_') && defined($key)) {
219 2
            $alias = $key;
220 2
        }
221 2
        return $alias;
222 2
    }
223 2
224 2
    public function addQuery($data)
225
    {
226
        if (!empty($data)) {
227
            if (is_array($data)) {
228
                $this->withURIQuery = http_build_query($data);
229
            } else if (is_string($data)) {
230
                $this->withURIQuery = $data;
231 1
            } else {
232
                throw new InvalidArgumentException('data must be array or string');
233 1
            }
234 1
        }
235 1
        return $this;
236 1
    }
237 1
238 1
    public function post($uri, $payload = null, array $options = array())
239
    {
240
        return $this->ini(Http::POST, $uri, $payload, $options);
241 1
    }
242 1
243
    /**
244
     * @param $uri
245
     * @param null $payload
246
     * @param array $options
247
     * @param null $response
248
     * @return string
249
     */
250
    public function quickPost($uri, $payload = null, array $options = array(), &$response = null)
251 1
    {
252
        $response = $this->post($uri, $payload, $options)->send();
253 1
        return $response->body;
254
    }
255
    /*  no body  */
256
257 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...
258
    {
259
        $options = array('url' => $url, 'method' => $method, 'data' => $data) + $options;
260
        $this->addOptions($options);
261
262
        return $this;
263 2
    }
264
265 2
    public function addOptions(array $options = array())
266 2
    {
267
        $this->options = $options + $this->options;
268 2
        $this->uri = $this->options['url'];
269
        return $this;
270
    }
271
272
    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...
273
    {
274
        return $this->ini(Http::PUT, $uri, $payload, $options);
275 2
    }
276
277 2
    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...
278 2
    {
279 2
        return $this->ini(Http::PATCH, $uri, $payload, $options);
280
    }
281
282
    public function get($uri, array $options = array())
283
    {
284
        return $this->ini(Http::GET, $uri, array(), $options);
285
    }
286
287
    /**
288 1
     * @param $uri
289
     * @param array $options
290 1
     * @param null $response
291
     * @return string
292
     */
293
    public function quickGet($uri, array $options = array(), &$response = null)
294
    {
295
        $response = $this->get($uri, $options)->send();
296
        return $response->body;
297
    }
298
299 1
    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...
300
    {
301 1
        return $this->ini(Http::OPTIONS, $uri, array(), $options);
302
    }
303
304
    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...
305
    {
306
        return $this->ini(Http::HEAD, $uri, array('CURLOPT_NOBODY' => true), $options);
307
    }
308
309 1
    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...
310
    {
311 1
        return $this->ini(Http::DELETE, $uri, array(), $options);
312
    }
313
314
    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...
315
    {
316
        return $this->ini(Http::TRACE, $uri, array(), $options);
317
    }
318
319 1
    /**
320
     * @return Response
321 1
     */
322
    public function send()
323
    {
324
        if (!$this->hasInitialized)
325
            $this->applyOptions();
326
        $response = $this->makeResponse();
327
        if ($this->endCallback) {
328
            $func = $this->endCallback;
329 1
            $func($response);
330
        }
331 1
        return $response;
332
    }
333
334
    public function applyOptions()
335
    {
336
        $curl = curl_init();
337
        $this->curlHandle = $curl;
338
        $this->prepare();
339 1
        $this->hasInitialized = true;
340
        return $this;
341 1
    }
342
343
    protected function prepare()
344
    {
345
        if (empty($this->options['url'])) {
346
            throw new InvalidArgumentException('url can not empty');
347
        }
348
349 2
        if (isset($this->options['retry_times'])) {
350
           $this->retryTimes = abs($this->options['retry_times']);
351 2
        }
352
353
        if (isset($this->options['retry_duration'])) {
354
           $this->retryDuration = abs($this->options['retry_duration']);
0 ignored issues
show
Documentation Bug introduced by
It seems like abs($this->options['retry_duration']) can also be of type double. However, the property $retryDuration is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
355
        }
356
357
        if (isset($this->options['data'])) {
358 2
            $this->options['data'] = is_array($this->options['data']) ? http_build_query($this->options['data']) : $this->options['data'];//for better compatibility
359
        }
360
        if (isset($this->withURIQuery)) {
361 2
            $this->options['url'] .= strpos($this->options['url'], '?') === FALSE ? '?' : '&';
362 2
            $this->options['url'] .= $this->withURIQuery;
363 2
        }
364 2
        if (isset($this->options['callback'])) {
365 2
            $this->onEnd($this->options['callback']);
366
            unset($this->options['callback']);
367
        }
368
        //swap ip and host
369
        if (!empty($this->options['ip'])) {
370
            $matches = array();
371 2
            preg_match('/\/\/([^\/]+)/', $this->options['url'], $matches);
372 1
            $host = $matches[1];
373 1
            if (empty($this->options['headers']) || !is_array($this->options['headers'])) {
374 2
                $this->options['headers'] = array('Host: ' . $host);
375 2
            } else {
376 2
                $this->options['headers'][] = 'Host: ' . $host;
377
            }
378 2
            $this->options['url'] = preg_replace('/\/\/([^\/]+)/', '//' . $this->options['ip'], $this->options['url']);
379
            unset($this->options['ip']);
380
            unset($host);
381
        }
382
        //process version
383
        if (!empty($this->options['http_version'])) {
384 2
            $version = $this->options['http_version'];
385
            if ($version == '1.0') {
386 2
                $this->options['CURLOPT_HTTP_VERSION'] = CURLOPT_HTTP_VERSION_1_0;
387 2
            } elseif ($version == '1.1') {
388 2
                $this->options['CURLOPT_HTTP_VERSION'] = CURLOPT_HTTP_VERSION_1_1;
389 2
            }
390 2
391
            unset($version);
392
        }
393
394
        //convert secs to milliseconds
395
        if (defined('CURLOPT_TIMEOUT_MS')) {
396 2
            if (!isset($this->options['timeout_ms'])) {
397
                $this->options['timeout_ms'] = intval($this->options['timeout'] * 1000);
398 2
            } else {
399 2
                $this->options['timeout_ms'] = intval($this->options['timeout_ms']);
400
            }
401
        }
402
403 2
        $cURLOptions = self::filterAndRaw($this->options);
404 1
405
        curl_setopt_array($this->curlHandle, $cURLOptions);
406 1
407
        return $this;
408 2
    }
409 1
410
    public function onEnd(callable $callback)
411 1
    {
412
        if (!is_callable($callback)) {
413 2
            throw new InvalidArgumentException('callback not is callable :' . print_r($callback, 1));
414
        }
415
416 2
        $this->endCallback = $callback;
417 2
        return $this;
418 2
    }
419 2
420 1
    protected static function filterAndRaw(array &$options)
421 1
    {
422 1
        $opts = array();
423 2
        foreach ($options as $key => $val) {
424
            $alias = self::optionAlias($key);
425 2
            $options[$alias] = $val;
426 2
            if ($alias) {
427
                $opts[constant($alias)] = $val;
428 2
            }
429
            unset($options[$key]);
430 2
        }
431 2
        return $opts;
432 2
    }
433 2
434 2
435 2
    public function makeResponse($isMultiCurl = false)
436 2
    {
437
        $handle = $this->curlHandle;
438
        $body = $errno = null;
439 2
        Helper::retry($this->retryTimes, function()use(&$body, &$errno, $isMultiCurl, $handle){
440
            $body = $isMultiCurl ? curl_multi_getcontent($handle) : curl_exec($handle);
441 2
            $errno = curl_errno($handle);
442 2
            var_dump(curl_error($handle), time());
0 ignored issues
show
Security Debugging Code introduced by
var_dump(curl_error($handle), time()); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
443
            ob_flush();
444 2
            flush();
445
            return 0 == $errno;
446
        }, $this->retryDuration);
447
448
        $info = curl_getinfo($this->curlHandle);
449
        $error = curl_error($this->curlHandle);
450
        $response = Response::create($this, $body, $info, $errno, $error);
451
        if (!is_null(self::$logger)) {
452
            self::log($response);
453
        }
454
455
        return $response;
456 2
    }
457 2
458 2
    private static function log(Response $response)
459 2
    {
460 1
        if ($response->hasErrors()) {
461
            self::$logger->error($response->request->getURI() . "\t" . $response->error, array(
0 ignored issues
show
Bug introduced by
The method getURI() does not seem to exist on object<MultiHttp\Request>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
462 2
                'response' => print_r($response, 1),
463
            ));
464
        }
465 2
466 2
    }
467
}
468