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.

Curl::getInfo()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 2
c 1
b 0
f 1
nc 1
nop 1
dl 0
loc 4
rs 10
1
<?php
2
3
namespace Curl;
4
5
class Curl
6
{
7
    const VERSION = '6.0.0';
8
    const DEFAULT_TIMEOUT = 30;
9
10
    public static $RFC2616 = array(
11
        // RFC2616: "any CHAR except CTLs or separators".
12
        // CHAR           = <any US-ASCII character (octets 0 - 127)>
13
        // CTL            = <any US-ASCII control character
14
        //                  (octets 0 - 31) and DEL (127)>
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% 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...
15
        // separators     = "(" | ")" | "<" | ">" | "@"
0 ignored issues
show
Unused Code Comprehensibility introduced by
41% 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...
16
        //                | "," | ";" | ":" | "\" | <">
17
        //                | "/" | "[" | "]" | "?" | "="
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% 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...
18
        //                | "{" | "}" | SP | HT
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...
19
        // SP             = <US-ASCII SP, space (32)>
20
        // HT             = <US-ASCII HT, horizontal-tab (9)>
21
        // <">            = <US-ASCII double-quote mark (34)>
22
        '!', '#', '$', '%', '&', "'", '*', '+', '-', '.', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
23
        'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
24
        'Y', 'Z', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
25
        'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '|', '~',
26
    );
27
    public static $RFC6265 = array(
28
        // RFC6265: "US-ASCII characters excluding CTLs, whitespace DQUOTE, comma, semicolon, and backslash".
29
        // %x21
30
        '!',
31
        // %x23-2B
32
        '#', '$', '%', '&', "'", '(', ')', '*', '+',
33
        // %x2D-3A
34
        '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':',
35
        // %x3C-5B
36
        '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
37
        'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[',
38
        // %x5D-7E
39
        ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
40
        's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
41
    );
42
43
    public $curl;
44
    public $id = null;
45
46
    public $error = false;
47
    public $errorCode = 0;
48
    public $errorMessage = null;
49
50
    public $curlError = false;
51
    public $curlErrorCode = 0;
52
    public $curlErrorMessage = null;
53
54
    public $httpError = false;
55
    public $httpStatusCode = 0;
56
    public $httpErrorMessage = null;
57
58
    public $baseUrl = null;
59
    public $url = null;
60
    public $requestHeaders = null;
61
    public $responseHeaders = null;
62
    public $rawResponseHeaders = '';
63
    public $responseCookies = array();
64
    public $response = null;
65
    public $rawResponse = null;
66
67
    public $beforeSendFunction = null;
68
    public $downloadCompleteFunction = null;
69
    public $successFunction = null;
70
    public $errorFunction = null;
71
    public $completeFunction = null;
72
    public $fileHandle = null;
73
74
    private $cookies = array();
75
    private $headers = array();
76
    private $options = array();
77
78
    private $jsonDecoder = null;
79
    private $jsonPattern = '/^(?:application|text)\/(?:[a-z]+(?:[\.-][0-9a-z]+){0,}[\+\.]|x-)?json(?:-[a-z]+)?/i';
80
    private $xmlDecoder = null;
81
    private $xmlPattern = '~^(?:text/|application/(?:atom\+|rss\+)?)xml~i';
82
    private $defaultDecoder = null;
83
84
    private static $deferredProperties = array(
85
        'effectiveUrl',
86
        'totalTime',
87
    );
88
89
    /**
90
     * Construct
91
     *
92
     * @access public
93
     * @param  $base_url
94
     * @throws \ErrorException
95
     */
96
    public function __construct($base_url = null)
97
    {
98
        if (!extension_loaded('curl')) {
99
            throw new \ErrorException('cURL library is not loaded');
100
        }
101
102
        $this->curl = curl_init();
103
        $this->id = uniqid('', true);
104
        $this->setDefaultUserAgent();
105
        $this->setDefaultJsonDecoder();
106
        $this->setDefaultXmlDecoder();
107
        $this->setDefaultTimeout();
108
        $this->setOpt(CURLINFO_HEADER_OUT, true);
109
        $this->setOpt(CURLOPT_HEADERFUNCTION, array($this, 'headerCallback'));
110
        $this->setOpt(CURLOPT_RETURNTRANSFER, true);
111
        $this->headers = new CaseInsensitiveArray();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Curl\CaseInsensitiveArray() of type object<Curl\CaseInsensitiveArray> is incompatible with the declared type array of property $headers.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
112
        $this->setURL($base_url);
113
        $this->rfc2616 = array_fill_keys(self::$RFC2616, true);
0 ignored issues
show
Bug introduced by
The property rfc2616 does not seem to exist. Did you mean RFC2616?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
114
        $this->rfc6265 = array_fill_keys(self::$RFC6265, true);
0 ignored issues
show
Bug introduced by
The property rfc6265 does not seem to exist. Did you mean RFC6265?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
115
    }
116
117
    /**
118
     * Before Send
119
     *
120
     * @access public
121
     * @param  $callback
122
     */
123
    public function beforeSend($callback)
124
    {
125
        $this->beforeSendFunction = $callback;
126
    }
127
128
    /**
129
     * Build Post Data
130
     *
131
     * @access public
132
     * @param  $data
133
     *
134
     * @return array|string
135
     */
136
    public function buildPostData($data)
137
    {
138
        $binary_data = false;
139
        if (is_array($data)) {
140
            // Return JSON-encoded string when the request's content-type is JSON.
141
            if (isset($this->headers['Content-Type']) &&
142
                preg_match($this->jsonPattern, $this->headers['Content-Type'])) {
143
                $json_str = json_encode($data);
144
                if (!($json_str === false)) {
145
                    $data = $json_str;
146
                }
147
            } else {
148
                // Manually build a single-dimensional array from a multi-dimensional array as using curl_setopt($ch,
149
                // CURLOPT_POSTFIELDS, $data) doesn't correctly handle multi-dimensional arrays when files are
150
                // referenced.
151
                if (self::is_array_multidim($data)) {
152
                    $data = self::array_flatten_multidim($data);
153
                }
154
155
                // Modify array values to ensure any referenced files are properly handled depending on the support of
156
                // the @filename API or CURLFile usage. This also fixes the warning "curl_setopt(): The usage of the
157
                // @filename API for file uploading is deprecated. Please use the CURLFile class instead". Ignore
158
                // non-file values prefixed with the @ character.
159
                foreach ($data as $key => $value) {
160
                    if (is_string($value) && strpos($value, '@') === 0 && is_file(substr($value, 1))) {
161
                        $binary_data = true;
162
                        if (class_exists('CURLFile')) {
163
                            $data[$key] = new \CURLFile(substr($value, 1));
164
                        }
165
                    } elseif ($value instanceof \CURLFile) {
0 ignored issues
show
Bug introduced by
The class CURLFile does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
166
                        $binary_data = true;
167
                    }
168
                }
169
            }
170
        }
171
172
        if (!$binary_data && (is_array($data) || is_object($data))) {
173
            $data = http_build_query($data, '', '&');
174
        }
175
176
        return $data;
177
    }
178
179
    /**
180
     * Call
181
     *
182
     * @access public
183
     */
184
    public function call()
185
    {
186
        $args = func_get_args();
187
        $function = array_shift($args);
188
        if (is_callable($function)) {
189
            array_unshift($args, $this);
190
            call_user_func_array($function, $args);
191
        }
192
    }
193
194
    /**
195
     * Close
196
     *
197
     * @access public
198
     */
199
    public function close()
200
    {
201
        if (is_resource($this->curl)) {
202
            curl_close($this->curl);
203
        }
204
        $this->options = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $options.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
205
        $this->jsonDecoder = null;
206
        $this->xmlDecoder = null;
207
        $this->defaultDecoder = null;
208
    }
209
210
    /**
211
     * Complete
212
     *
213
     * @access public
214
     * @param  $callback
215
     */
216
    public function complete($callback)
217
    {
218
        $this->completeFunction = $callback;
219
    }
220
221
    /**
222
     * Progress
223
     *
224
     * @access public
225
     * @param  $callback
226
     */
227
    public function progress($callback)
228
    {
229
        $this->setOpt(CURLOPT_PROGRESSFUNCTION, $callback);
230
        $this->setOpt(CURLOPT_NOPROGRESS, false);
231
    }
232
233
    /**
234
     * Delete
235
     *
236
     * @access public
237
     * @param  $url
238
     * @param  $query_parameters
239
     * @param  $data
240
     *
241
     * @return string
242
     */
243
    public function delete($url, $query_parameters = array(), $data = array())
244
    {
245
        if (is_array($url)) {
246
            $data = $query_parameters;
247
            $query_parameters = $url;
248
            $url = $this->baseUrl;
249
        }
250
251
        $this->setURL($url, $query_parameters);
252
        $this->setOpt(CURLOPT_CUSTOMREQUEST, 'DELETE');
253
        $this->setOpt(CURLOPT_POSTFIELDS, $this->buildPostData($data));
254
        return $this->exec();
255
    }
256
257
    /**
258
     * Download Complete
259
     *
260
     * @access private
261
     * @param  $fh
262
     */
263
    private function downloadComplete($fh)
264
    {
265
        if (!$this->error && $this->downloadCompleteFunction) {
266
            rewind($fh);
267
            $this->call($this->downloadCompleteFunction, $fh);
268
            $this->downloadCompleteFunction = null;
269
        }
270
271
        if (is_resource($fh)) {
272
            fclose($fh);
273
        }
274
275
        // Fix "PHP Notice: Use of undefined constant STDOUT" when reading the
276
        // PHP script from stdin. Using null causes "Warning: curl_setopt():
277
        // supplied argument is not a valid File-Handle resource".
278
        if (!defined('STDOUT')) {
279
            define('STDOUT', fopen('php://stdout', 'w'));
280
        }
281
282
        // Reset CURLOPT_FILE with STDOUT to avoid: "curl_exec(): CURLOPT_FILE
283
        // resource has gone away, resetting to default".
284
        $this->setOpt(CURLOPT_FILE, STDOUT);
285
286
        // Reset CURLOPT_RETURNTRANSFER to tell cURL to return subsequent
287
        // responses as the return value of curl_exec(). Without this,
288
        // curl_exec() will revert to returning boolean values.
289
        $this->setOpt(CURLOPT_RETURNTRANSFER, true);
290
    }
291
292
    /**
293
     * Download
294
     *
295
     * @access public
296
     * @param  $url
297
     * @param  $mixed_filename
298
     *
299
     * @return boolean
300
     */
301
    public function download($url, $mixed_filename)
302
    {
303
        if (is_callable($mixed_filename)) {
304
            $this->downloadCompleteFunction = $mixed_filename;
305
            $fh = tmpfile();
306
        } else {
307
            $filename = $mixed_filename;
308
            $fh = fopen($filename, 'wb');
309
        }
310
311
        $this->setOpt(CURLOPT_FILE, $fh);
312
        $this->get($url);
313
        $this->downloadComplete($fh);
314
315
        return ! $this->error;
316
    }
317
318
    /**
319
     * Error
320
     *
321
     * @access public
322
     * @param  $callback
323
     */
324
    public function error($callback)
325
    {
326
        $this->errorFunction = $callback;
327
    }
328
329
    /**
330
     * Exec
331
     *
332
     * @access public
333
     * @param  $ch
334
     *
335
     * @return mixed Returns the value provided by parseResponse.
336
     */
337
    public function exec($ch = null)
338
    {
339
        if ($ch === null) {
340
            $this->responseCookies = array();
341
            $this->call($this->beforeSendFunction);
342
            $this->rawResponse = curl_exec($this->curl);
343
            $this->curlErrorCode = curl_errno($this->curl);
344
            $this->curlErrorMessage = curl_error($this->curl);
345
        } else {
346
            $this->rawResponse = curl_multi_getcontent($ch);
347
            $this->curlErrorMessage = curl_error($ch);
348
        }
349
        $this->curlError = !($this->curlErrorCode === 0);
350
351
        // Include additional error code information in error message when possible.
352
        if ($this->curlError && function_exists('curl_strerror')) {
353
            $this->curlErrorMessage =
354
                curl_strerror($this->curlErrorCode) . (
355
                    empty($this->curlErrorMessage) ? '' : ': ' . $this->curlErrorMessage
356
                );
357
        }
358
359
        $this->httpStatusCode = $this->getInfo(CURLINFO_HTTP_CODE);
360
        $this->httpError = in_array(floor($this->httpStatusCode / 100), array(4, 5));
361
        $this->error = $this->curlError || $this->httpError;
362
        $this->errorCode = $this->error ? ($this->curlError ? $this->curlErrorCode : $this->httpStatusCode) : 0;
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->error ? $this->cu...his->httpStatusCode : 0 can also be of type double. However, the property $errorCode 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...
363
364
        // NOTE: CURLINFO_HEADER_OUT set to true is required for requestHeaders
365
        // to not be empty (e.g. $curl->setOpt(CURLINFO_HEADER_OUT, true);).
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...
366
        if ($this->getOpt(CURLINFO_HEADER_OUT) === true) {
367
            $this->requestHeaders = $this->parseRequestHeaders($this->getInfo(CURLINFO_HEADER_OUT));
368
        }
369
        $this->responseHeaders = $this->parseResponseHeaders($this->rawResponseHeaders);
370
        $this->response = $this->parseResponse($this->responseHeaders, $this->rawResponse);
371
372
        $this->httpErrorMessage = '';
373
        if ($this->error) {
374
            if (isset($this->responseHeaders['Status-Line'])) {
375
                $this->httpErrorMessage = $this->responseHeaders['Status-Line'];
376
            }
377
        }
378
        $this->errorMessage = $this->curlError ? $this->curlErrorMessage : $this->httpErrorMessage;
379
380
        if (!$this->error) {
381
            $this->call($this->successFunction);
382
        } else {
383
            $this->call($this->errorFunction);
384
        }
385
386
        $this->call($this->completeFunction);
387
388
        // Close open file handles and reset the curl instance.
389
        if (!($this->fileHandle === null)) {
390
            $this->downloadComplete($this->fileHandle);
391
        }
392
393
        return $this->response;
394
    }
395
396
    /**
397
     * Get
398
     *
399
     * @access public
400
     * @param  $url
401
     * @param  $data
402
     *
403
     * @return mixed Returns the value provided by exec.
404
     */
405 View Code Duplication
    public function get($url, $data = 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...
406
    {
407
        if (is_array($url)) {
408
            $data = $url;
409
            $url = $this->baseUrl;
410
        }
411
        $this->setURL($url, $data);
412
        $this->setOpt(CURLOPT_CUSTOMREQUEST, 'GET');
413
        $this->setOpt(CURLOPT_HTTPGET, true);
414
        return $this->exec();
415
    }
416
417
    /**
418
     * Get Info
419
     *
420
     * @access public
421
     * @param  $opt
422
     *
423
     * @return mixed
424
     */
425
    public function getInfo($opt)
426
    {
427
        return curl_getinfo($this->curl, $opt);
428
    }
429
430
    /**
431
     * Get Opt
432
     *
433
     * @access public
434
     * @param  $option
435
     *
436
     * @return mixed
437
     */
438
    public function getOpt($option)
439
    {
440
        return isset($this->options[$option]) ? $this->options[$option] : null;
441
    }
442
443
    /**
444
     * Head
445
     *
446
     * @access public
447
     * @param  $url
448
     * @param  $data
449
     *
450
     * @return string
451
     */
452 View Code Duplication
    public function head($url, $data = 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...
453
    {
454
        if (is_array($url)) {
455
            $data = $url;
456
            $url = $this->baseUrl;
457
        }
458
        $this->setURL($url, $data);
459
        $this->setOpt(CURLOPT_CUSTOMREQUEST, 'HEAD');
460
        $this->setOpt(CURLOPT_NOBODY, true);
461
        return $this->exec();
462
    }
463
464
    /**
465
     * Header Callback
466
     *
467
     * @access public
468
     * @param  $ch
469
     * @param  $header
470
     *
471
     * @return integer
472
     */
473
    public function headerCallback($ch, $header)
474
    {
475
        if (preg_match('/^Set-Cookie:\s*([^=]+)=([^;]+)/mi', $header, $cookie) === 1) {
476
            $this->responseCookies[$cookie[1]] = trim($cookie[2], " \n\r\t\0\x0B");
477
        }
478
        $this->rawResponseHeaders .= $header;
479
        return strlen($header);
480
    }
481
482
    /**
483
     * Options
484
     *
485
     * @access public
486
     * @param  $url
487
     * @param  $data
488
     *
489
     * @return string
490
     */
491 View Code Duplication
    public function options($url, $data = 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...
492
    {
493
        if (is_array($url)) {
494
            $data = $url;
495
            $url = $this->baseUrl;
496
        }
497
        $this->setURL($url, $data);
498
        $this->unsetHeader('Content-Length');
499
        $this->setOpt(CURLOPT_CUSTOMREQUEST, 'OPTIONS');
500
        return $this->exec();
501
    }
502
503
    /**
504
     * Patch
505
     *
506
     * @access public
507
     * @param  $url
508
     * @param  $data
509
     *
510
     * @return string
511
     */
512
    public function patch($url, $data = array())
513
    {
514
        if (is_array($url)) {
515
            $data = $url;
516
            $url = $this->baseUrl;
517
        }
518
519
        if (is_array($data) && empty($data)) {
520
            $this->unsetHeader('Content-Length');
521
        }
522
523
        $this->setURL($url);
524
        $this->setOpt(CURLOPT_CUSTOMREQUEST, 'PATCH');
525
        $this->setOpt(CURLOPT_POSTFIELDS, $this->buildPostData($data));
526
        return $this->exec();
527
    }
528
529
    /**
530
     * Post
531
     *
532
     * @access public
533
     * @param  $url
534
     * @param  $data
535
     * @param  $follow_303_with_post
536
     *     If true, will cause 303 redirections to be followed using a POST request (default: false).
537
     *     Notes:
538
     *       - Redirections are only followed if the CURLOPT_FOLLOWLOCATION option is set to true.
539
     *       - According to the HTTP specs (see [1]), a 303 redirection should be followed using
540
     *         the GET method. 301 and 302 must not.
541
     *       - In order to force a 303 redirection to be performed using the same method, the
542
     *         underlying cURL object must be set in a special state (the CURLOPT_CURSTOMREQUEST
543
     *         option must be set to the method to use after the redirection). Due to a limitation
544
     *         of the cURL extension of PHP < 5.5.11 ([2], [3]) and of HHVM, it is not possible
545
     *         to reset this option. Using these PHP engines, it is therefore impossible to
546
     *         restore this behavior on an existing php-curl-class Curl object.
547
     *
548
     * @return string
549
     *
550
     * [1] https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.2
551
     * [2] https://github.com/php/php-src/pull/531
552
     * [3] http://php.net/ChangeLog-5.php#5.5.11
553
     */
554
    public function post($url, $data = array(), $follow_303_with_post = false)
555
    {
556
        if (is_array($url)) {
557
            $follow_303_with_post = (bool)$data;
558
            $data = $url;
559
            $url = $this->baseUrl;
560
        }
561
562
        $this->setURL($url);
563
564
        if ($follow_303_with_post) {
565
            $this->setOpt(CURLOPT_CUSTOMREQUEST, 'POST');
566
        } else {
567
            if (isset($this->options[CURLOPT_CUSTOMREQUEST])) {
568
                if ((version_compare(PHP_VERSION, '5.5.11') < 0) || defined('HHVM_VERSION')) {
569
                    trigger_error(
570
                        'Due to technical limitations of PHP <= 5.5.11 and HHVM, it is not possible to '
571
                        . 'perform a post-redirect-get request using a php-curl-class Curl object that '
572
                        . 'has already been used to perform other types of requests. Either use a new '
573
                        . 'php-curl-class Curl object or upgrade your PHP engine.',
574
                        E_USER_ERROR
575
                    );
576
                } else {
577
                    $this->setOpt(CURLOPT_CUSTOMREQUEST, null);
578
                }
579
            }
580
        }
581
582
        $this->setOpt(CURLOPT_POST, true);
583
        $this->setOpt(CURLOPT_POSTFIELDS, $this->buildPostData($data));
584
        return $this->exec();
585
    }
586
587
    /**
588
     * Put
589
     *
590
     * @access public
591
     * @param  $url
592
     * @param  $data
593
     *
594
     * @return string
595
     */
596 View Code Duplication
    public function put($url, $data = 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...
597
    {
598
        if (is_array($url)) {
599
            $data = $url;
600
            $url = $this->baseUrl;
601
        }
602
        $this->setURL($url);
603
        $this->setOpt(CURLOPT_CUSTOMREQUEST, 'PUT');
604
        $put_data = $this->buildPostData($data);
605
        if (empty($this->options[CURLOPT_INFILE]) && empty($this->options[CURLOPT_INFILESIZE])) {
606
            if (is_string($put_data)) {
607
                $this->setHeader('Content-Length', strlen($put_data));
608
            }
609
        }
610
        if (!empty($put_data)) {
611
            $this->setOpt(CURLOPT_POSTFIELDS, $put_data);
612
        }
613
        return $this->exec();
614
    }
615
616
    /**
617
     * Search
618
     *
619
     * @access public
620
     * @param  $url
621
     * @param  $data
622
     *
623
     * @return string
624
     */
625 View Code Duplication
    public function search($url, $data = 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...
626
    {
627
        if (is_array($url)) {
628
            $data = $url;
629
            $url = $this->baseUrl;
630
        }
631
        $this->setURL($url);
632
        $this->setOpt(CURLOPT_CUSTOMREQUEST, 'SEARCH');
633
        $put_data = $this->buildPostData($data);
634
        if (empty($this->options[CURLOPT_INFILE]) && empty($this->options[CURLOPT_INFILESIZE])) {
635
            if (is_string($put_data)) {
636
                $this->setHeader('Content-Length', strlen($put_data));
637
            }
638
        }
639
        if (!empty($put_data)) {
640
            $this->setOpt(CURLOPT_POSTFIELDS, $put_data);
641
        }
642
        return $this->exec();
643
    }
644
645
    /**
646
     * Set Basic Authentication
647
     *
648
     * @access public
649
     * @param  $username
650
     * @param  $password
651
     */
652
    public function setBasicAuthentication($username, $password = '')
653
    {
654
        $this->setOpt(CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
655
        $this->setOpt(CURLOPT_USERPWD, $username . ':' . $password);
656
    }
657
658
    /**
659
     * Set Digest Authentication
660
     *
661
     * @access public
662
     * @param  $username
663
     * @param  $password
664
     */
665
    public function setDigestAuthentication($username, $password = '')
666
    {
667
        $this->setOpt(CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
668
        $this->setOpt(CURLOPT_USERPWD, $username . ':' . $password);
669
    }
670
671
    /**
672
     * Set Cookie
673
     *
674
     * @access public
675
     * @param  $key
676
     * @param  $value
677
     */
678
    public function setCookie($key, $value)
679
    {
680
        $name_chars = array();
681
        foreach (str_split($key) as $name_char) {
682
            if (!isset($this->rfc2616[$name_char])) {
0 ignored issues
show
Bug introduced by
The property rfc2616 does not seem to exist. Did you mean RFC2616?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
683
                $name_chars[] = rawurlencode($name_char);
684
            } else {
685
                $name_chars[] = $name_char;
686
            }
687
        }
688
689
        $value_chars = array();
690
        foreach (str_split($value) as $value_char) {
691
            if (!isset($this->rfc6265[$value_char])) {
0 ignored issues
show
Bug introduced by
The property rfc6265 does not seem to exist. Did you mean RFC6265?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
692
                $value_chars[] = rawurlencode($value_char);
693
            } else {
694
                $value_chars[] = $value_char;
695
            }
696
        }
697
698
        $this->cookies[implode('', $name_chars)] = implode('', $value_chars);
699
        $this->setOpt(CURLOPT_COOKIE, implode('; ', array_map(function ($k, $v) {
700
            return $k . '=' . $v;
701
        }, array_keys($this->cookies), array_values($this->cookies))));
702
    }
703
704
    /**
705
     * Get cookie.
706
     *
707
     * @access public
708
     * @param  $key
709
     *
710
     * @return mixed
711
     */
712
    public function getCookie($key)
713
    {
714
        return $this->getResponseCookie($key);
715
    }
716
717
    /**
718
     * Get response cookie.
719
     *
720
     * @access public
721
     * @param  $key
722
     *
723
     * @return mixed
724
     */
725
    public function getResponseCookie($key)
726
    {
727
        return isset($this->responseCookies[$key]) ? $this->responseCookies[$key] : null;
728
    }
729
730
    /**
731
     * Set Port
732
     *
733
     * @access public
734
     * @param  $port
735
     */
736
    public function setPort($port)
737
    {
738
        $this->setOpt(CURLOPT_PORT, intval($port));
739
    }
740
741
    /**
742
     * Set Connect Timeout
743
     *
744
     * @access public
745
     * @param  $seconds
746
     */
747
    public function setConnectTimeout($seconds)
748
    {
749
        $this->setOpt(CURLOPT_CONNECTTIMEOUT, $seconds);
750
    }
751
752
    /**
753
     * Set Cookie String
754
     *
755
     * @access public
756
     * @param  $string
757
     *
758
     * @return bool
759
     */
760
    public function setCookieString($string)
761
    {
762
        return $this->setOpt(CURLOPT_COOKIE, $string);
763
    }
764
765
    /**
766
     * Set Cookie File
767
     *
768
     * @access public
769
     * @param  $cookie_file
770
     */
771
    public function setCookieFile($cookie_file)
772
    {
773
        $this->setOpt(CURLOPT_COOKIEFILE, $cookie_file);
774
    }
775
776
    /**
777
     * Set Cookie Jar
778
     *
779
     * @access public
780
     * @param  $cookie_jar
781
     */
782
    public function setCookieJar($cookie_jar)
783
    {
784
        $this->setOpt(CURLOPT_COOKIEJAR, $cookie_jar);
785
    }
786
787
    /**
788
     * Set Default JSON Decoder
789
     *
790
     * @access public
791
     * @param  $assoc
792
     * @param  $depth
793
     * @param  $options
794
     */
795
    public function setDefaultJsonDecoder()
796
    {
797
        $args = func_get_args();
798
        $this->jsonDecoder = function ($response) use ($args) {
799
            array_unshift($args, $response);
800
801
            // Call json_decode() without the $options parameter in PHP
802
            // versions less than 5.4.0 as the $options parameter was added in
803
            // PHP version 5.4.0.
804
            if (version_compare(PHP_VERSION, '5.4.0', '<')) {
805
                $args = array_slice($args, 0, 3);
0 ignored issues
show
Bug introduced by
Consider using a different name than the imported variable $args, or did you forget to import by reference?

It seems like you are assigning to a variable which was imported through a use statement which was not imported by reference.

For clarity, we suggest to use a different name or import by reference depending on whether you would like to have the change visibile in outer-scope.

Change not visible in outer-scope

$x = 1;
$callable = function() use ($x) {
    $x = 2; // Not visible in outer scope. If you would like this, how
            // about using a different variable name than $x?
};

$callable();
var_dump($x); // integer(1)

Change visible in outer-scope

$x = 1;
$callable = function() use (&$x) {
    $x = 2;
};

$callable();
var_dump($x); // integer(2)
Loading history...
806
            }
807
808
            $json_obj = call_user_func_array('json_decode', $args);
809
            if (!($json_obj === null)) {
810
                $response = $json_obj;
811
            }
812
            return $response;
813
        };
814
    }
815
816
    /**
817
     * Set Default XML Decoder
818
     *
819
     * @access public
820
     */
821
    public function setDefaultXmlDecoder()
822
    {
823
        $this->xmlDecoder = function ($response) {
824
            $xml_obj = @simplexml_load_string($response);
825
            if (!($xml_obj === false)) {
826
                $response = $xml_obj;
827
            }
828
            return $response;
829
        };
830
    }
831
832
    /**
833
     * Set Default Decoder
834
     *
835
     * @access public
836
     * @param  $decoder string|callable
837
     */
838
    public function setDefaultDecoder($decoder = 'json')
839
    {
840
        if (is_callable($decoder)) {
841
            $this->defaultDecoder = $decoder;
842
        } else {
843
            if ($decoder === 'json') {
844
                $this->defaultDecoder = $this->jsonDecoder;
845
            } elseif ($decoder === 'xml') {
846
                $this->defaultDecoder = $this->xmlDecoder;
847
            }
848
        }
849
    }
850
851
    /**
852
     * Set Default Timeout
853
     *
854
     * @access public
855
     */
856
    public function setDefaultTimeout()
857
    {
858
        $this->setTimeout(self::DEFAULT_TIMEOUT);
859
    }
860
861
    /**
862
     * Set Default User Agent
863
     *
864
     * @access public
865
     */
866
    public function setDefaultUserAgent()
867
    {
868
        $user_agent = 'PHP-Curl-Class/' . self::VERSION . ' (+https://github.com/php-curl-class/php-curl-class)';
869
        $user_agent .= ' PHP/' . PHP_VERSION;
870
        $curl_version = curl_version();
871
        $user_agent .= ' curl/' . $curl_version['version'];
872
        $this->setUserAgent($user_agent);
873
    }
874
875
    /**
876
     * Set Header
877
     *
878
     * @access public
879
     * @param  $key
880
     * @param  $value
881
     */
882
    public function setHeader($key, $value)
883
    {
884
        $this->headers[$key] = $value;
885
        $headers = array();
886
        foreach ($this->headers as $key => $value) {
887
            $headers[] = $key . ': ' . $value;
888
        }
889
        $this->setOpt(CURLOPT_HTTPHEADER, $headers);
890
    }
891
892
    /**
893
     * Set JSON Decoder
894
     *
895
     * @access public
896
     * @param  $function
897
     */
898
    public function setJsonDecoder($function)
899
    {
900
        if (is_callable($function)) {
901
            $this->jsonDecoder = $function;
902
        }
903
    }
904
905
    /**
906
     * Set XML Decoder
907
     *
908
     * @access public
909
     * @param  $function
910
     */
911
    public function setXmlDecoder($function)
912
    {
913
        if (is_callable($function)) {
914
            $this->xmlDecoder = $function;
915
        }
916
    }
917
918
    /**
919
     * Set Opt
920
     *
921
     * @access public
922
     * @param  $option
923
     * @param  $value
924
     *
925
     * @return boolean
926
     */
927
    public function setOpt($option, $value)
928
    {
929
        $required_options = array(
930
            CURLOPT_RETURNTRANSFER => 'CURLOPT_RETURNTRANSFER',
931
        );
932
933
        if (in_array($option, array_keys($required_options), true) && !($value === true)) {
934
            trigger_error($required_options[$option] . ' is a required option', E_USER_WARNING);
935
        }
936
937
        $success = curl_setopt($this->curl, $option, $value);
938
        if ($success) {
939
            $this->options[$option] = $value;
940
        }
941
        return $success;
942
    }
943
944
    /**
945
     * Set Opts
946
     *
947
     * @access public
948
     * @param  $options
949
     *
950
     * @return boolean
951
     *   Returns true if all options were successfully set. If an option could not be successfully set, false is
952
     *   immediately returned, ignoring any future options in the options array. Similar to curl_setopt_array().
953
     */
954
    public function setOpts($options)
955
    {
956
        foreach ($options as $option => $value) {
957
            if (!$this->setOpt($option, $value)) {
958
                return false;
959
            }
960
        }
961
        return true;
962
    }
963
964
    /**
965
     * Set Referer
966
     *
967
     * @access public
968
     * @param  $referer
969
     */
970
    public function setReferer($referer)
971
    {
972
        $this->setReferrer($referer);
973
    }
974
975
    /**
976
     * Set Referrer
977
     *
978
     * @access public
979
     * @param  $referrer
980
     */
981
    public function setReferrer($referrer)
982
    {
983
        $this->setOpt(CURLOPT_REFERER, $referrer);
984
    }
985
986
    /**
987
     * Set Timeout
988
     *
989
     * @access public
990
     * @param  $seconds
991
     */
992
    public function setTimeout($seconds)
993
    {
994
        $this->setOpt(CURLOPT_TIMEOUT, $seconds);
995
    }
996
997
    /**
998
     * Set Url
999
     *
1000
     * @access public
1001
     * @param  $url
1002
     * @param  $data
1003
     */
1004
    public function setURL($url, $data = array())
1005
    {
1006
        $this->baseUrl = $url;
1007
        $this->url = $this->buildURL($url, $data);
1008
        $this->setOpt(CURLOPT_URL, $this->url);
1009
    }
1010
1011
    /**
1012
     * Set User Agent
1013
     *
1014
     * @access public
1015
     * @param  $user_agent
1016
     */
1017
    public function setUserAgent($user_agent)
1018
    {
1019
        $this->setOpt(CURLOPT_USERAGENT, $user_agent);
1020
    }
1021
1022
    /**
1023
     * Success
1024
     *
1025
     * @access public
1026
     * @param  $callback
1027
     */
1028
    public function success($callback)
1029
    {
1030
        $this->successFunction = $callback;
1031
    }
1032
1033
    /**
1034
     * Unset Header
1035
     *
1036
     * @access public
1037
     * @param  $key
1038
     */
1039
    public function unsetHeader($key)
1040
    {
1041
        $this->setHeader($key, '');
1042
        unset($this->headers[$key]);
1043
    }
1044
1045
    /**
1046
     * Verbose
1047
     *
1048
     * @access public
1049
     * @param  bool $on
1050
     * @param  resource $output
1051
     */
1052 View Code Duplication
    public function verbose($on = true, $output = STDERR)
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...
1053
    {
1054
        // Turn off CURLINFO_HEADER_OUT for verbose to work. This has the side
1055
        // effect of causing Curl::requestHeaders to be empty.
1056
        if ($on) {
1057
            $this->setOpt(CURLINFO_HEADER_OUT, false);
1058
        }
1059
        $this->setOpt(CURLOPT_VERBOSE, $on);
1060
        $this->setOpt(CURLOPT_STDERR, $output);
1061
    }
1062
1063
    /**
1064
     * Destruct
1065
     *
1066
     * @access public
1067
     */
1068
    public function __destruct()
1069
    {
1070
        $this->close();
1071
    }
1072
1073
    public function __get($name)
1074
    {
1075
        $return = null;
1076
        if (in_array($name, self::$deferredProperties) && is_callable(array($this, $getter = '__get_' . $name))) {
1077
            $return = $this->$name = $this->$getter();
1078
        }
1079
        return $return;
1080
    }
1081
1082
    /**
1083
     * Get Effective Url
1084
     *
1085
     * @access private
1086
     */
1087
    private function __get_effectiveUrl()
1088
    {
1089
        return $this->getInfo(CURLINFO_EFFECTIVE_URL);
1090
    }
1091
1092
    /**
1093
     * Get Total Time
1094
     *
1095
     * @access private
1096
     */
1097
    private function __get_totalTime()
1098
    {
1099
        return $this->getInfo(CURLINFO_TOTAL_TIME);
1100
    }
1101
1102
    /**
1103
     * Build Url
1104
     *
1105
     * @access private
1106
     * @param  $url
1107
     * @param  $data
1108
     *
1109
     * @return string
1110
     */
1111
    private function buildURL($url, $data = array())
1112
    {
1113
        return $url . (empty($data) ? '' : '?' . http_build_query($data, '', '&'));
1114
    }
1115
1116
    /**
1117
     * Parse Headers
1118
     *
1119
     * @access private
1120
     * @param  $raw_headers
1121
     *
1122
     * @return array
1123
     */
1124
    private function parseHeaders($raw_headers)
1125
    {
1126
        $raw_headers = preg_split('/\r\n/', $raw_headers, null, PREG_SPLIT_NO_EMPTY);
1127
        $http_headers = new CaseInsensitiveArray();
1128
1129
        $raw_headers_count = count($raw_headers);
1130
        for ($i = 1; $i < $raw_headers_count; $i++) {
1131
            list($key, $value) = explode(':', $raw_headers[$i], 2);
1132
            $key = trim($key);
1133
            $value = trim($value);
1134
            // Use isset() as array_key_exists() and ArrayAccess are not compatible.
1135
            if (isset($http_headers[$key])) {
1136
                $http_headers[$key] .= ',' . $value;
1137
            } else {
1138
                $http_headers[$key] = $value;
1139
            }
1140
        }
1141
1142
        return array(isset($raw_headers['0']) ? $raw_headers['0'] : '', $http_headers);
1143
    }
1144
1145
    /**
1146
     * Parse Request Headers
1147
     *
1148
     * @access private
1149
     * @param  $raw_headers
1150
     *
1151
     * @return array
1152
     */
1153
    private function parseRequestHeaders($raw_headers)
1154
    {
1155
        $request_headers = new CaseInsensitiveArray();
1156
        list($first_line, $headers) = $this->parseHeaders($raw_headers);
1157
        $request_headers['Request-Line'] = $first_line;
1158
        foreach ($headers as $key => $value) {
1159
            $request_headers[$key] = $value;
1160
        }
1161
        return $request_headers;
1162
    }
1163
1164
    /**
1165
     * Parse Response
1166
     *
1167
     * @access private
1168
     * @param  $response_headers
1169
     * @param  $raw_response
1170
     *
1171
     * @return mixed
1172
     *   Provided the content-type is determined to be json or xml:
1173
     *     Returns stdClass object when the default json decoder is used and the content-type is json.
1174
     *     Returns SimpleXMLElement object when the default xml decoder is used and the content-type is xml.
1175
     */
1176
    private function parseResponse($response_headers, $raw_response)
1177
    {
1178
        $response = $raw_response;
1179
        if (isset($response_headers['Content-Type'])) {
1180
            if (preg_match($this->jsonPattern, $response_headers['Content-Type'])) {
1181
                $json_decoder = $this->jsonDecoder;
1182
                if (is_callable($json_decoder)) {
1183
                    $response = $json_decoder($response);
1184
                }
1185
            } elseif (preg_match($this->xmlPattern, $response_headers['Content-Type'])) {
1186
                $xml_decoder = $this->xmlDecoder;
1187
                if (is_callable($xml_decoder)) {
1188
                    $response = $xml_decoder($response);
1189
                }
1190
            } else {
1191
                $decoder = $this->defaultDecoder;
1192
                if (is_callable($decoder)) {
1193
                    $response = $decoder($response);
1194
                }
1195
            }
1196
        }
1197
1198
        return $response;
1199
    }
1200
1201
    /**
1202
     * Parse Response Headers
1203
     *
1204
     * @access private
1205
     * @param  $raw_response_headers
1206
     *
1207
     * @return array
1208
     */
1209
    private function parseResponseHeaders($raw_response_headers)
1210
    {
1211
        $response_header_array = explode("\r\n\r\n", $raw_response_headers);
1212
        $response_header  = '';
1213
        for ($i = count($response_header_array) - 1; $i >= 0; $i--) {
1214
            if (stripos($response_header_array[$i], 'HTTP/') === 0) {
1215
                $response_header = $response_header_array[$i];
1216
                break;
1217
            }
1218
        }
1219
1220
        $response_headers = new CaseInsensitiveArray();
1221
        list($first_line, $headers) = $this->parseHeaders($response_header);
1222
        $response_headers['Status-Line'] = $first_line;
1223
        foreach ($headers as $key => $value) {
1224
            $response_headers[$key] = $value;
1225
        }
1226
        return $response_headers;
1227
    }
1228
1229
    /**
1230
     * Is Array Assoc
1231
     *
1232
     * @access public
1233
     * @param  $array
1234
     *
1235
     * @return boolean
1236
     */
1237
    public static function is_array_assoc($array)
1238
    {
1239
        return (bool)count(array_filter(array_keys($array), 'is_string'));
1240
    }
1241
1242
    /**
1243
     * Is Array Multidim
1244
     *
1245
     * @access public
1246
     * @param  $array
1247
     *
1248
     * @return boolean
1249
     */
1250
    public static function is_array_multidim($array)
1251
    {
1252
        if (!is_array($array)) {
1253
            return false;
1254
        }
1255
1256
        return (bool)count(array_filter($array, 'is_array'));
1257
    }
1258
1259
    /**
1260
     * Array Flatten Multidim
1261
     *
1262
     * @access public
1263
     * @param  $array
1264
     * @param  $prefix
1265
     *
1266
     * @return array
1267
     */
1268
    public static function array_flatten_multidim($array, $prefix = false)
1269
    {
1270
        $return = array();
1271
        if (is_array($array) || is_object($array)) {
1272
            if (empty($array)) {
1273
                $return[$prefix] = '';
1274
            } else {
1275
                foreach ($array as $key => $value) {
1276
                    if (is_scalar($value)) {
1277
                        if ($prefix) {
1278
                            $return[$prefix . '[' . $key . ']'] = $value;
1279
                        } else {
1280
                            $return[$key] = $value;
1281
                        }
1282
                    } else {
1283
                        if ($value instanceof \CURLFile) {
0 ignored issues
show
Bug introduced by
The class CURLFile does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
1284
                            $return[$key] = $value;
1285
                        } else {
1286
                            $return = array_merge(
1287
                                $return,
1288
                                self::array_flatten_multidim(
1289
                                    $value,
1290
                                    $prefix ? $prefix . '[' . $key . ']' : $key
0 ignored issues
show
Documentation introduced by
$prefix ? $prefix . '[' . $key . ']' : $key is of type integer|string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1291
                                )
1292
                            );
1293
                        }
1294
                    }
1295
                }
1296
            }
1297
        } elseif ($array === null) {
1298
            $return[$prefix] = $array;
1299
        }
1300
        return $return;
1301
    }
1302
}
1303