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 ( c5fc1e...fcfb9f )
by sunsky
02:08
created

Request::hasEndCallback()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
rs 10
ccs 3
cts 3
cp 1
cc 1
eloc 2
nc 1
nop 0
crap 1
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 2
    public $encoding;
50
    public $payload;
51 2
    protected $options = array(
52
        'CURLOPT_MAXREDIRS' => 10,
53 2
        'header' => true,
54 2
        'method' => self::GET,
55
        'transfer' => true,
56
        'follow_location' => true,
57 1
        'timeout' => 0);
58 1
    protected $endCallback;
59
    protected $withURIQuery;
60
    protected $hasInitialized = false;
61 2
62 2
    protected function __construct()
63
    {
64
65 2
    }
66 2
67
    public static function create()
68
    {
69 2
        return new self;
70 2
    }
71
72
    public static function setLogger($logger)
73 2
    {
74 2
        self::$logger = $logger;
75
    }
76
77
    /**
78
     * Specify   timeout
79
     * @param float|int $timeout seconds to timeout the HTTP call
80
     * @return Request
81 2
     */
82
    public function timeout($timeout)
83
    {
84 2
        $this->timeout = $timeout;
85 2
        return $this;
86
    }
87
88 2
    public function noFollow()
89
    {
90
        return $this->follow(0);
91
    }
92
93
    /**
94
     * If the response is a 301 or 302 redirect, automatically
95 1
     * send off another request to that location
96 1
     * @param int $follow follow or not to follow or maximal number of redirects
97 1
     * @return Request
98 1
     */
99 1
    public function follow(int $follow = self::MAX_REDIRECTS_DEFAULT)
100 1
    {
101
        $this->maxRedirects = abs($follow);
102
        $this->followRedirects = $follow > 0;
103
        return $this;
104
    }
105 1
106
    public function endCallback()
107
    {
108 1
        return $this->endCallback;
109 1
    }
110
111
    public function hasEndCallback()
112 2
    {
113 2
        return isset($this->endCallback);
114 2
    }
115
116 2
    public function uri($uri)
117
    {
118
        $this->uri = $uri;
119 2
        return $this;
120 2
    }
121 2
122
    public function hasCert()
123
    {
124 2
        return isset($this->cert) && isset($this->key);
125 2
    }
126
127 2
    /**
128 1
     * Use Client Side Cert Authentication
129 1
     * @param string $key file path to client key
130
     * @param string $cert file path to client cert
131 2
     * @param string $passphrase for client key
132 2
     * @param string $encoding default PEM
133 2
     * @return Request
134
     */
135
    public function cert($cert, $key, $passphrase = null, $encoding = 'PEM')
136 2
    {
137
        $this->cert = $cert;
138
        $this->key = $key;
139
        $this->passphrase = $passphrase;
140
        $this->encoding = $encoding;
141
        return $this;
142
    }
143
144
    public function body($payload, $mimeType = null)
145
    {
146
        $this->mime($mimeType);
147
        $this->payload = $payload;
148
        // Iserntentially don't call _serializePayload yet.  Wait until
149 1
        // we actually send off the request to convert payload to string.
150 1
        // At that time, the `serialized_payload` is set accordingly.
151
        return $this;
152
    }
153 1
    public function mime($mime)
154 1
    {
155
        if (empty($mime)) return $this;
156
        $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...
157
        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...
158
            $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...
159
        }
160
        return $this;
161
    }
162
    public function addHeader($header_name, $value)
163
    {
164
        $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...
165 2
        return $this;
166 2
    }
167
168
    public function addHeaders(array $headers)
169
    {
170
        foreach ($headers as $header => $value) {
171
            $this->addHeader($header, $value);
172 1
        }
173 1
        return $this;
174 1
    }
175 1
    public function expectsType($mime)
176 1
    {
177 1
        return $this->expects($mime);
178
    }
179 1
    public function sendType($mime)
180
    {
181
        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...
182 2
    }
183 2
    public function expects($mime)
184 2
    {
185 2
        if (empty($mime)) return $this;
186 2
        $this->expected_type = Mime::getFullMime($mime);
187
        return $this;
188
    }
189 2
    /**
190
     * @param $field alias or field name
191 2
     * @return bool|mixed
192 1
     */
193 1
    public function getIni($field)
194 1
    {
195 1
        $alias = self::optionAlias($field);
196 1
        return isset($this->options[$alias]) ? $this->options[$alias] : false;
197
    }
198
199
    /**
200 1
     * @param $key
201 1
     * @return mixed
202 1
     */
203
    protected static function optionAlias($key)
204
    {
205 2
        $alias = false;
206
        if (isset(self::$curlAlias[$key])) {
207
            $alias = self::$curlAlias[$key];
208
        } elseif ((substr($key, 0, strlen('CURLOPT_')) == 'CURLOPT_') && defined($key)) {
209
            $alias = $key;
210
        }
211
        return $alias;
212
    }
213
214
    public function addQuery($data)
215 2
    {
216 2
        if (!empty($data)) {
217 2
            if (is_array($data)) {
218
                $this->withURIQuery = http_build_query($data);
219 1
            } else if (is_string($data)) {
220
                $this->withURIQuery = $data;
221
            } else {
222
                throw new InvalidArgumentException('data must be array or string');
223 2
            }
224 2
        }
225
        return $this;
226 2
    }
227
228
    public function post($uri, $payload = null, array $options = array())
229 2
    {
230
        return $this->ini(Http::POST, $uri, $payload, $options);
231
    }
232 2
233 2
    /*  no body  */
234 2
235 2 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...
236 2
    {
237 2
        $options = array('url' => $url, 'method' => $method, 'data' => $data) + $options;
238
        $this->addOptions($options);
239
240 2
        return $this;
241 2
    }
242
243
    public function addOptions(array $options = array())
244
    {
245
        $this->options = $options + $this->options;
246
        $this->uri = $this->options['url'];
247 2
        return $this;
248 2
    }
249 2
250 2
    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...
251 2
    {
252 2
        return $this->ini(Http::PUT, $uri, $payload, $options);
253
    }
254 2
255
    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...
256 2
    {
257 2
        return $this->ini(Http::PATCH, $uri, $payload, $options);
258 2
    }
259 2
260 2
    public function get($uri, array $options = array())
261 2
    {
262 2
        return $this->ini(Http::GET, $uri, array(), $options);
263
    }
264
265
    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...
266
    {
267
        return $this->ini(Http::OPTIONS, $uri, array(), $options);
268
    }
269
270
    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...
271
    {
272
        return $this->ini(Http::HEAD, $uri, array('CURLOPT_NOBODY' => true), $options);
273
    }
274
275
    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...
276
    {
277
        return $this->ini(Http::DELETE, $uri, array(), $options);
278
    }
279
280
    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...
281
    {
282
        return $this->ini(Http::TRACE, $uri, array(), $options);
283
    }
284
285
    /**
286
     * @return Response
287
     */
288
    public function send()
289
    {
290
        if (!$this->hasInitialized)
291
            $this->applyOptions();
292
        $response = $this->makeResponse();
293
        if ($this->endCallback) {
294
            $func = $this->endCallback;
295
            $func($response);
296
        }
297
        return $response;
298
    }
299
300
    public function applyOptions()
301
    {
302
        $curl = curl_init();
303
        $this->curlHandle = $curl;
304
        $this->prepare();
305
        $this->hasInitialized = true;
306
        return $this;
307
    }
308
309
    protected function prepare()
310
    {
311
        if (empty($this->options['url'])) {
312
            throw new InvalidArgumentException('url can not empty');
313
        }
314
315
        if (isset($this->options['data'])) {
316
            $this->options['data'] = is_array($this->options['data']) ? http_build_query($this->options['data']) : $this->options['data'];//for better compatibility
317
        }
318
        if (isset($this->withURIQuery)) {
319
            $this->options['url'] .= strpos($this->options['url'], '?') === FALSE ? '?' : '&';
320
            $this->options['url'] .= $this->withURIQuery;
321
        }
322
        if (isset($this->options['callback'])) {
323
            $this->onEnd($this->options['callback']);
324
            unset($this->options['callback']);
325
        }
326
        //swap ip and host
327
        if (!empty($this->options['ip'])) {
328
            $matches = array();
329
            preg_match('/\/\/([^\/]+)/', $this->options['url'], $matches);
330
            $host = $matches[1];
331
            if (empty($this->options['headers']) || !is_array($this->options['headers'])) {
332
                $this->options['headers'] = array('Host: ' . $host);
333
            } else {
334
                $this->options['headers'][] = 'Host: ' . $host;
335
            }
336
            $this->options['url'] = preg_replace('/\/\/([^\/]+)/', '//' . $this->options['ip'], $this->options['url']);
337
            unset($this->options['ip']);
338
            unset($host);
339
        }
340
        //process version
341
        if (!empty($this->options['http_version'])) {
342
            $version = $this->options['http_version'];
343
            if ($version == '1.0') {
344
                $this->options['CURLOPT_HTTP_VERSION'] = CURLOPT_HTTP_VERSION_1_0;
345
            } elseif ($version == '1.1') {
346
                $this->options['CURLOPT_HTTP_VERSION'] = CURLOPT_HTTP_VERSION_1_1;
347
            }
348
349
            unset($version);
350
        }
351
352
        //convert secs to milliseconds
353
        if (defined('CURLOPT_TIMEOUT_MS')) {
354
            if (!isset($this->options['timeout_ms'])) {
355
                $this->options['timeout_ms'] = intval($this->options['timeout'] * 1000);
356
            } else {
357
                $this->options['timeout_ms'] = intval($this->options['timeout_ms']);
358
            }
359
        }
360
361
362
        $cURLOptions = self::filterAndRaw($this->options);
363
364
        curl_setopt_array($this->curlHandle, $cURLOptions);
365
366
        return $this;
367
    }
368
369
    public function onEnd(callable $callback)
370
    {
371
        if (!is_callable($callback)) {
372
            throw new InvalidArgumentException('callback not is callable :' . print_r($callback, 1));
373
        }
374
375
        $this->endCallback = $callback;
376
        return $this;
377
    }
378
379
    protected static function filterAndRaw(array &$options)
380
    {
381
        $opts = array();
382
        foreach ($options as $key => $val) {
383
            $alias = self::optionAlias($key);
384
            $options[$alias] = $val;
385
            if ($alias) {
386
                $opts[constant($alias)] = $val;
387
            }
388
            unset($options[$key]);
389
        }
390
        return $opts;
391
    }
392
393
    public function makeResponse($isMultiCurl = false)
394
    {
395
        $body = $isMultiCurl ? curl_multi_getcontent($this->curlHandle) : curl_exec($this->curlHandle);
396
        $info = curl_getinfo($this->curlHandle);
397
        $errno = curl_errno($this->curlHandle);
398
        $error = curl_error($this->curlHandle);
399
        $response = Response::create($this, $body, $info, $errno, $error);
400
        if (!is_null(self::$logger)) {
401
            self::log($response);
402
        }
403
404
        return $response;
405
    }
406
407
    private static function log(Response $response)
408
    {
409
        if ($response->hasErrors()) {
410
            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...
411
                'response' => print_r($response, 1),
412
            ));
413
        }
414
415
    }
416
}
417