Passed
Push — master ( cfc71f...0262f3 )
by KwangSeob
02:06
created

JiraClient::filterNullVariable()   A

Complexity

Conditions 6
Paths 7

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 8
nc 7
nop 1
dl 0
loc 15
rs 9.2222
c 0
b 0
f 0
1
<?php
2
3
namespace JiraRestApi;
4
5
use JiraRestApi\Configuration\ConfigurationInterface;
6
use JiraRestApi\Configuration\DotEnvConfiguration;
7
use Monolog\Handler\StreamHandler;
8
use Monolog\Logger as Logger;
9
use Psr\Log\LoggerInterface;
10
11
/**
12
 * Interact jira server with REST API.
13
 */
14
class JiraClient
15
{
16
    /**
17
     * Json Mapper.
18
     *
19
     * @var \JsonMapper
20
     */
21
    protected $json_mapper;
22
23
    /**
24
     * HTTP response code.
25
     *
26
     * @var string
27
     */
28
    protected $http_response;
29
30
    /**
31
     * JIRA REST API URI.
32
     *
33
     * @var string
34
     */
35
    private $api_uri = '/rest/api/2';
36
37
    /**
38
     * CURL instance.
39
     *
40
     * @var resource
41
     */
42
    protected $curl;
43
44
    /**
45
     * Monolog instance.
46
     *
47
     * @var \Monolog\Logger
48
     */
49
    protected $log;
50
51
    /**
52
     * Jira Rest API Configuration.
53
     *
54
     * @var ConfigurationInterface
55
     */
56
    protected $configuration;
57
58
    /**
59
     * json en/decode options
60
     *
61
     * @var int
62
     */
63
    protected $jsonOptions;
64
65
    /**
66
     * Constructor.
67
     *
68
     * @param ConfigurationInterface $configuration
69
     * @param LoggerInterface        $logger
70
     * @param string                 $path
71
     *
72
     * @throws JiraException
73
     * @throws \Exception
74
     */
75
    public function __construct(ConfigurationInterface $configuration = null, LoggerInterface $logger = null, $path = './')
76
    {
77
        if ($configuration === null) {
78
            if (!file_exists($path.'.env')) {
79
                // If calling the getcwd() on laravel it will returning the 'public' directory.
80
                $path = '../';
81
            }
82
            $this->configuration = new DotEnvConfiguration($path);
83
        } else {
84
            $this->configuration = $configuration;
85
        }
86
87
        $this->json_mapper = new \JsonMapper();
88
89
        // Fix "\JiraRestApi\JsonMapperHelper::class" syntax error, unexpected 'class' (T_CLASS), expecting identifier (T_STRING) or variable (T_VARIABLE) or '{' or '$'
90
        $this->json_mapper->undefinedPropertyHandler = [new \JiraRestApi\JsonMapperHelper(), 'setUndefinedProperty'];
91
92
        // Properties that are annotated with `@var \DateTimeInterface` should result in \DateTime objects being created.
93
        $this->json_mapper->classMap['\\'.\DateTimeInterface::class] = \DateTime::class;
94
95
        // create logger
96
        if ($this->configuration->getJiraLogEnabled()) {
97
            if ($logger) {
98
                $this->log = $logger;
0 ignored issues
show
Documentation Bug introduced by
$logger is of type Psr\Log\LoggerInterface, but the property $log was declared to be of type Monolog\Logger. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof 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 given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
99
            } else {
100
                $this->log = new Logger('JiraClient');
101
                $this->log->pushHandler(new StreamHandler(
102
                    $this->configuration->getJiraLogFile(),
103
                    $this->convertLogLevel($this->configuration->getJiraLogLevel())
104
                ));
105
            }
106
        } else {
107
            $this->log = new Logger('JiraClient');
108
            $this->log->pushHandler(new NoOperationMonologHandler());
109
        }
110
111
        $this->http_response = 200;
112
113
        if ($this->configuration->getUseV3RestApi()) {
114
            $this->setRestApiV3();
115
        }
116
117
        $this->curl = curl_init();
0 ignored issues
show
Documentation Bug introduced by
It seems like curl_init() can also be of type false. However, the property $curl is declared as type resource. 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...
118
119
        $this->jsonOptions = JSON_UNESCAPED_UNICODE;
120
121
        if (PHP_MAJOR_VERSION >= 7)
122
        {
123
            if (PHP_MAJOR_VERSION === 7 && PHP_MINOR_VERSION >= 3)
124
            {
125
                $this->jsonOptions |= JSON_THROW_ON_ERROR ;
126
            } else { // if php major great than 7 then always setting JSON_THROW_ON_ERROR
127
                $this->jsonOptions |= JSON_THROW_ON_ERROR ;
128
            }
129
        }
130
    }
131
132
    /**
133
     * Convert log level.
134
     *
135
     * @param $log_level
136
     *
137
     * @return int
138
     */
139
    private function convertLogLevel($log_level)
140
    {
141
        $log_level = strtoupper($log_level);
142
143
        switch ($log_level) {
144
            case 'EMERGENCY':
145
                return Logger::EMERGENCY;
146
            case 'ALERT':
147
                return Logger::ALERT;
148
            case 'CRITICAL':
149
                return Logger::CRITICAL;
150
            case 'ERROR':
151
                return Logger::ERROR;
152
            case 'WARNING':
153
                return Logger::WARNING;
154
            case 'NOTICE':
155
                return Logger::NOTICE;
156
            case 'DEBUG':
157
                return Logger::DEBUG;
158
            case 'INFO':
159
                return Logger::INFO;
160
            default:
161
                return Logger::WARNING;
162
        }
163
    }
164
165
    /**
166
     * Serilize only not null field.
167
     *
168
     * @param array $haystack
169
     *
170
     * @return array
171
     */
172
    protected function filterNullVariable($haystack)
173
    {
174
        foreach ($haystack as $key => $value) {
175
            if (is_array($value)) {
176
                $haystack[$key] = $this->filterNullVariable($haystack[$key]);
177
            } elseif (is_object($value)) {
178
                $haystack[$key] = $this->filterNullVariable(get_class_vars(get_class($value)));
179
            }
180
181
            if (is_null($haystack[$key]) || empty($haystack[$key])) {
182
                unset($haystack[$key]);
183
            }
184
        }
185
186
        return $haystack;
187
    }
188
189
    /**
190
     * Execute REST request.
191
     *
192
     * @param string $context        Rest API context (ex.:issue, search, etc..)
193
     * @param string $post_data
194
     * @param string $custom_request [PUT|DELETE]
195
     * @param string $cookieFile     cookie file
196
     *
197
     * @throws JiraException
198
     *
199
     * @return string
200
     */
201
    public function exec($context, $post_data = null, $custom_request = null, $cookieFile = null)
202
    {
203
        $url = $this->createUrlByContext($context);
204
205
        if (is_string($post_data)) {
206
            $this->log->info("Curl $custom_request: $url JsonData=".$post_data);
207
        } elseif (is_array($post_data)) {
0 ignored issues
show
introduced by
The condition is_array($post_data) is always false.
Loading history...
208
            $this->log->info("Curl $custom_request: $url JsonData=".json_encode($post_data, JSON_UNESCAPED_UNICODE));
209
        }
210
211
        curl_reset($this->curl);
212
        $ch = $this->curl;
213
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
214
        curl_setopt($ch, CURLOPT_URL, $url);
215
216
        // post_data
217
        if (!is_null($post_data)) {
218
            // PUT REQUEST
219
            if (!is_null($custom_request) && $custom_request == 'PUT') {
220
                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
221
                curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
222
            }
223
            if (!is_null($custom_request) && $custom_request == 'DELETE') {
224
                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
225
            } else {
226
                curl_setopt($ch, CURLOPT_POST, true);
227
                curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
228
            }
229
        } else {
230
            if (!is_null($custom_request) && $custom_request == 'DELETE') {
231
                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
232
            }
233
        }
234
235
        $this->authorization($ch, $cookieFile);
236
237
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $this->getConfiguration()->isCurlOptSslVerifyHost());
238
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $this->getConfiguration()->isCurlOptSslVerifyPeer());
239
        curl_setopt($ch, CURLOPT_USERAGENT, $this->getConfiguration()->getCurlOptUserAgent());
240
241
        // curl_setopt(): CURLOPT_FOLLOWLOCATION cannot be activated when an open_basedir is set
242
        if (!function_exists('ini_get') || !ini_get('open_basedir')) {
243
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
244
        }
245
246
        curl_setopt($ch, CURLOPT_ENCODING, '');
247
        curl_setopt(
248
            $ch,
249
            CURLOPT_HTTPHEADER,
250
            ['Accept: */*', 'Content-Type: application/json', 'X-Atlassian-Token: no-check']
251
        );
252
253
        curl_setopt($ch, CURLOPT_VERBOSE, $this->getConfiguration()->isCurlOptVerbose());
254
255
        // Add proxy settings to the curl.
256
        $this->proxyConfigCurlHandle($ch);
257
258
        $this->log->debug('Curl exec='.$url);
259
        $response = curl_exec($ch);
260
261
        // if request failed or have no result.
262
        if (!$response) {
263
            $this->http_response = curl_getinfo($ch, CURLINFO_HTTP_CODE);
264
            $body = curl_error($ch);
265
266
            /*
267
             * 201: The request has been fulfilled, resulting in the creation of a new resource.
268
             * 204: The server successfully processed the request, but is not returning any content.
269
             */
270
            if ($this->http_response === 204 || $this->http_response === 201 || $this->http_response === 200) {
271
                return true;
0 ignored issues
show
Bug Best Practice introduced by
The expression return true returns the type true which is incompatible with the documented return type string.
Loading history...
272
            }
273
274
            // HostNotFound, No route to Host, etc Network error
275
            $msg = sprintf('CURL Error: http response=%d, %s', $this->http_response, $body);
276
277
            $this->log->error($msg);
278
279
            throw new JiraException($msg);
280
        } else {
281
            // if request was ok, parsing http response code.
282
            $this->http_response = curl_getinfo($ch, CURLINFO_HTTP_CODE);
283
284
            // don't check 301, 302 because setting CURLOPT_FOLLOWLOCATION
285
            if ($this->http_response != 200 && $this->http_response != 201) {
286
                throw new JiraException('CURL HTTP Request Failed: Status Code : '
287
                    .$this->http_response.', URL:'.$url
288
                    ."\nError Message : ".$response, $this->http_response);
0 ignored issues
show
Bug introduced by
Are you sure $response of type string|true can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

288
                    ."\nError Message : "./** @scrutinizer ignore-type */ $response, $this->http_response);
Loading history...
289
            }
290
        }
291
292
        return $response;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $response also could return the type true which is incompatible with the documented return type string.
Loading history...
293
    }
294
295
    /**
296
     * Create upload handle.
297
     *
298
     * @param string $url         Request URL
299
     * @param string $upload_file Filename
300
     *
301
     * @return resource
302
     */
303
    private function createUploadHandle($url, $upload_file, $ch)
304
    {
305
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
306
        curl_setopt($ch, CURLOPT_URL, $url);
307
308
        // send file
309
        curl_setopt($ch, CURLOPT_POST, true);
310
311
        if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 5) {
312
            $attachments = realpath($upload_file);
313
            $filename = basename($upload_file);
314
315
            curl_setopt(
316
                $ch,
317
                CURLOPT_POSTFIELDS,
318
                ['file' => '@'.$attachments.';filename='.$filename]
319
            );
320
321
            $this->log->debug('using legacy file upload');
322
        } else {
323
            // CURLFile require PHP > 5.5
324
            $attachments = new \CURLFile(realpath($upload_file));
325
            $attachments->setPostFilename(basename($upload_file));
326
327
            curl_setopt(
328
                $ch,
329
                CURLOPT_POSTFIELDS,
330
                ['file' => $attachments]
331
            );
332
333
            $this->log->debug('using CURLFile='.var_export($attachments, true));
334
        }
335
336
        $this->authorization($ch);
337
338
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $this->getConfiguration()->isCurlOptSslVerifyHost());
339
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $this->getConfiguration()->isCurlOptSslVerifyPeer());
340
341
        $this->proxyConfigCurlHandle($ch);
342
343
        // curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); cannot be activated when an open_basedir is set
344
        if (!function_exists('ini_get') || !ini_get('open_basedir')) {
345
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
346
        }
347
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
348
            'Accept: */*',
349
            'Content-Type: multipart/form-data',
350
            'X-Atlassian-Token: nocheck',
351
        ]);
352
353
        curl_setopt($ch, CURLOPT_VERBOSE, $this->getConfiguration()->isCurlOptVerbose());
354
355
        $this->log->debug('Curl exec='.$url);
356
357
        return $ch;
358
    }
359
360
    /**
361
     * File upload.
362
     *
363
     * @param string $context       url context
364
     * @param array  $filePathArray upload file path.
365
     *
366
     * @throws JiraException
367
     *
368
     * @return array
369
     */
370
    public function upload($context, $filePathArray)
371
    {
372
        $url = $this->createUrlByContext($context);
373
374
        $results = [];
375
376
        $ch = curl_init();
377
378
        $idx = 0;
379
        foreach ($filePathArray as $file) {
380
            $this->createUploadHandle($url, $file, $ch);
381
382
            $response = curl_exec($ch);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_exec() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

382
            $response = curl_exec(/** @scrutinizer ignore-type */ $ch);
Loading history...
383
384
            // if request failed or have no result.
385
            if (!$response) {
386
                $http_response = curl_getinfo($ch, CURLINFO_HTTP_CODE);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_getinfo() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

386
                $http_response = curl_getinfo(/** @scrutinizer ignore-type */ $ch, CURLINFO_HTTP_CODE);
Loading history...
387
                $body = curl_error($ch);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_error() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

387
                $body = curl_error(/** @scrutinizer ignore-type */ $ch);
Loading history...
388
389
                if ($http_response === 204 || $http_response === 201 || $http_response === 200) {
390
                    $results[$idx] = $response;
391
                } else {
392
                    $msg = sprintf('CURL Error: http response=%d, %s', $http_response, $body);
393
                    $this->log->error($msg);
394
395
                    curl_close($ch);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_close() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

395
                    curl_close(/** @scrutinizer ignore-type */ $ch);
Loading history...
396
397
                    throw new JiraException($msg);
398
                }
399
            } else {
400
                $results[$idx] = $response;
401
            }
402
        }
403
404
        curl_close($ch);
405
406
        return $results;
407
    }
408
409
    /**
410
     * @param array $chArr
411
     * @param $mh
412
     * @param $body
413
     * @param $result_code
414
     *
415
     * @throws \JiraRestApi\JiraException
416
     */
417
    protected function closeCURLHandle(array $chArr, $mh, $body, $result_code)
418
    {
419
        foreach ($chArr as $ch) {
420
            $this->log->debug('CURL Close handle..');
421
            curl_multi_remove_handle($mh, $ch);
422
        }
423
        $this->log->debug('CURL Multi Close handle..');
424
        curl_multi_close($mh);
425
        if ($result_code != 200) {
426
            // @TODO $body might have not been defined
427
            throw new JiraException('CURL Error: = '.$body, $result_code);
428
        }
429
    }
430
431
    /**
432
     * Get URL by context.
433
     *
434
     * @param string $context
435
     *
436
     * @return string
437
     */
438
    protected function createUrlByContext($context)
439
    {
440
        $host = $this->getConfiguration()->getJiraHost();
441
442
        return $host.$this->api_uri.'/'.preg_replace('/\//', '', $context, 1);
443
    }
444
445
    /**
446
     * Add authorize to curl request.
447
     *
448
     * @param resource $ch
449
     */
450
    protected function authorization($ch, $cookieFile = null)
451
    {
452
        // use cookie
453
        if ($this->getConfiguration()->isCookieAuthorizationEnabled()) {
454
            if ($cookieFile === null) {
455
                $cookieFile = $this->getConfiguration()->getCookieFile();
456
            }
457
458
            curl_setopt($ch, CURLOPT_COOKIEJAR, $cookieFile);
459
            curl_setopt($ch, CURLOPT_COOKIEFILE, $cookieFile);
460
461
            $this->log->debug('Using cookie..');
462
        }
463
464
        // if cookie file not exist, using id/pwd login
465
        if (!file_exists($cookieFile)) {
466
            $username = $this->getConfiguration()->getJiraUser();
467
            $password = $this->getConfiguration()->getJiraPassword();
468
            curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
469
        }
470
    }
471
472
    /**
473
     * Jira Rest API Configuration.
474
     *
475
     * @return ConfigurationInterface
476
     */
477
    public function getConfiguration()
478
    {
479
        return $this->configuration;
480
    }
481
482
    /**
483
     * Set a custom Jira API URI for the request.
484
     *
485
     * @param string $api_uri
486
     */
487
    public function setAPIUri($api_uri)
488
    {
489
        $this->api_uri = $api_uri;
490
    }
491
492
    /**
493
     * convert to query array to http query parameter.
494
     *
495
     * @param $paramArray
496
     *
497
     * @return string
498
     */
499
    public function toHttpQueryParameter($paramArray)
500
    {
501
        $queryParam = '?';
502
503
        foreach ($paramArray as $key => $value) {
504
            $v = null;
505
506
            // some param field(Ex: expand) type is array.
507
            if (is_array($value)) {
508
                $v = implode(',', $value);
509
            } else {
510
                $v = $value;
511
            }
512
513
            $queryParam .= $key.'='.$v.'&';
514
        }
515
516
        return $queryParam;
517
    }
518
519
    /**
520
     * download and save into outDir.
521
     *
522
     * @param $url full url
0 ignored issues
show
Bug introduced by
The type JiraRestApi\full was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
523
     * @param $outDir save dir
524
     * @param $file save filename
0 ignored issues
show
Bug introduced by
The type JiraRestApi\save was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
525
     * @param $cookieFile cookie filename
0 ignored issues
show
Bug introduced by
The type JiraRestApi\cookie was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
526
     *
527
     * @throws JiraException
528
     *
529
     * @return bool|mixed
530
     */
531
    public function download($url, $outDir, $file, $cookieFile = null)
532
    {
533
        $file = fopen($outDir.DIRECTORY_SEPARATOR.$file, 'w');
534
535
        curl_reset($this->curl);
536
        $ch = $this->curl;
537
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
538
        curl_setopt($ch, CURLOPT_URL, $url);
539
540
        // output to file handle
541
        curl_setopt($ch, CURLOPT_FILE, $file);
542
543
        $this->authorization($ch, $cookieFile);
544
545
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $this->getConfiguration()->isCurlOptSslVerifyHost());
546
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $this->getConfiguration()->isCurlOptSslVerifyPeer());
547
        $this->proxyConfigCurlHandle($ch);
548
549
        // curl_setopt(): CURLOPT_FOLLOWLOCATION cannot be activated when an open_basedir is set
550
        if (!function_exists('ini_get') || !ini_get('open_basedir')) {
551
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
552
        }
553
554
        curl_setopt(
555
            $ch,
556
            CURLOPT_HTTPHEADER,
557
            ['Accept: */*', 'Content-Type: application/json', 'X-Atlassian-Token: no-check']
558
        );
559
560
        curl_setopt($ch, CURLOPT_VERBOSE, $this->getConfiguration()->isCurlOptVerbose());
561
562
        if ($this->isRestApiV3()) {
563
            curl_setopt($ch, CURLOPT_HTTPHEADER, ['x-atlassian-force-account-id: true']);
564
        }
565
566
        $this->log->debug('Curl exec='.$url);
567
        $response = curl_exec($ch);
568
569
        // if request failed.
570
        if (!$response) {
571
            $this->http_response = curl_getinfo($ch, CURLINFO_HTTP_CODE);
572
            $body = curl_error($ch);
573
            fclose($file);
0 ignored issues
show
Bug introduced by
It seems like $file can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

573
            fclose(/** @scrutinizer ignore-type */ $file);
Loading history...
574
575
            /*
576
             * 201: The request has been fulfilled, resulting in the creation of a new resource.
577
             * 204: The server successfully processed the request, but is not returning any content.
578
             */
579
            if ($this->http_response === 204 || $this->http_response === 201) {
580
                return true;
581
            }
582
583
            // HostNotFound, No route to Host, etc Network error
584
            $msg = sprintf('CURL Error: http response=%d, %s', $this->http_response, $body);
585
586
            $this->log->error($msg);
587
588
            throw new JiraException($msg);
589
        } else {
590
            // if request was ok, parsing http response code.
591
            $this->http_response = curl_getinfo($ch, CURLINFO_HTTP_CODE);
592
            fclose($file);
593
594
            // don't check 301, 302 because setting CURLOPT_FOLLOWLOCATION
595
            if ($this->http_response != 200 && $this->http_response != 201) {
596
                throw new JiraException('CURL HTTP Request Failed: Status Code : '
597
                    .$this->http_response.', URL:'.$url
598
                    ."\nError Message : ".$response, $this->http_response);
0 ignored issues
show
Bug introduced by
Are you sure $response of type string|true can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

598
                    ."\nError Message : "./** @scrutinizer ignore-type */ $response, $this->http_response);
Loading history...
599
            }
600
        }
601
602
        return $response;
603
    }
604
605
    /**
606
     * setting cookie file path.
607
     *
608
     * @param $cookieFile
609
     *
610
     * @return $this
611
     */
612
    public function setCookieFile($cookieFile)
613
    {
614
        $this->cookieFile = $cookieFile;
0 ignored issues
show
Bug Best Practice introduced by
The property cookieFile does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
615
616
        return $this;
617
    }
618
619
    /**
620
     * Config a curl handle with proxy configuration (if set) from ConfigurationInterface.
621
     *
622
     * @param $ch
623
     */
624
    private function proxyConfigCurlHandle($ch)
625
    {
626
        // Add proxy settings to the curl.
627
        if ($this->getConfiguration()->getProxyServer()) {
628
            curl_setopt($ch, CURLOPT_PROXY, $this->getConfiguration()->getProxyServer());
629
            curl_setopt($ch, CURLOPT_PROXYPORT, $this->getConfiguration()->getProxyPort());
630
631
            $username = $this->getConfiguration()->getProxyUser();
632
            $password = $this->getConfiguration()->getProxyPassword();
633
            curl_setopt($ch, CURLOPT_PROXYUSERPWD, "$username:$password");
634
        }
635
    }
636
637
    /**
638
     * setting REST API url to V3.
639
     *
640
     * @return $this
641
     */
642
    public function setRestApiV3()
643
    {
644
        $this->api_uri = '/rest/api/3';
645
646
        return $this;
647
    }
648
649
    /**
650
     * check whether current API is v3.
651
     *
652
     * @return bool
653
     */
654
    public function isRestApiV3()
655
    {
656
        return $this->configuration->getUseV3RestApi();
657
    }
658
659
    /**
660
     * setting JSON en/decoding options
661
     *
662
     * @param int $jsonOptions
663
     * @return $this
664
     */
665
    public function setJsonOptions(int $jsonOptions)
666
    {
667
        $this->jsonOptions = $jsonOptions;
668
669
        return $this;
670
    }
671
672
    /**
673
     * get json en/decode options
674
     *
675
     * @return int
676
     */
677
    public function getJsonOptions()
678
    {
679
        return $this->jsonOptions;
680
    }
681
}
682