Passed
Push — master ( 12b79a...29c6ce )
by Fran
09:13
created

Service::addAuthHeader()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 3
ccs 0
cts 3
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
namespace PSFS\base;
3
4
use PSFS\base\config\Config;
5
use PSFS\base\types\helpers\SecurityHelper;
6
use PSFS\base\types\helpers\ServiceHelper;
7
8
/**
9
 * Class Service
10
 * @package PSFS\base
11
 */
12
class Service extends Singleton
13
{
14
    const CTYPE_JSON = 'application/json';
15
    const CTYPE_MULTIPART = 'multipart/form-data';
16
    const CTYPE_FORM = 'application/x-www-form-urlencoded';
17
    const CTYPE_PLAIN = 'text/plain';
18
    const PSFS_TRACK_HEADER = 'X-PSFS-UID';
19
20
    /**
21
     * @var String Url de destino de la llamada
22
     */
23
    private $url;
24
    /**
25
     * @var array Parámetros de la llamada
26
     */
27
    private $params;
28
    /**
29
     * @var array Opciones llamada
30
     */
31
    private $options;
32
    /**
33
     * @var array Cabeceras de la llamada
34
     */
35
    private $headers;
36
    /**
37
     * @var string type
38
     */
39
    private $type;
40
    /**
41
     * @var resource $con
42
     */
43
    private $con;
44
    /**
45
     * @var string $result
46
     */
47
    private $result;
48
    /**
49
     * @var mixed
50
     */
51
    private $info = [];
52
53
    /**
54
     * @Injectable
55
     * @var \PSFS\base\Logger Log de las llamadas
56
     */
57
    protected $log;
58
    /**
59
     * @Injectable
60
     * @var \PSFS\base\Cache $cache
61
     */
62
    protected $cache;
63
    /**
64
     * @var bool
65
     */
66
    protected $isJson = true;
67
    /**
68
     * @var bool
69
     */
70
    protected $isMultipart = false;
71
72 2
    private function closeConnection() {
73 2
        if(null !== $this->con) {
74 1
            curl_close($this->con);
75
        }
76 2
    }
77
78
    public function __destruct()
79
    {
80
        $this->closeConnection();
81
    }
82
83
    /**
84
     * @return String
85
     */
86 1
    public function getUrl()
87
    {
88 1
        return $this->url;
89
    }
90
91
    /**
92
     * @param String $url
93
     */
94 1
    public function setUrl($url)
95
    {
96 1
        $this->url = $url;
97 1
        $this->initialize();
98 1
    }
99
100
    /**
101
     * @return string
102
     */
103
    public function getResult()
104
    {
105
        return $this->result;
106
    }
107
108
    /**
109
     * @param string $result
110
     */
111
    public function setResult($result)
112
    {
113
        $this->result = $result;
114
    }
115
116
    /**
117
     * @return array
118
     */
119
    public function getParams()
120
    {
121
        return $this->params;
122
    }
123
124
    /**
125
     * Add request param
126
     *
127
     * @param $key
128
     * @param null $value
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $value is correct as it would always require null to be passed?
Loading history...
129
     *
130
     * @return \PSFS\base\Service
131
     */
132
    public function addParam($key, $value = NULL)
133
    {
134
        $this->params[$key] = $value;
135
136
        return $this;
137
    }
138
139
    /**
140
     * @return array
141
     */
142
    public function getOptions()
143
    {
144
        return $this->options;
145
    }
146
147
    /**
148
     * Add request param
149
     *
150
     * @param $key
151
     * @param null $value
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $value is correct as it would always require null to be passed?
Loading history...
152
     *
153
     * @return \PSFS\base\Service
154
     */
155
    public function addOption($key, $value = NULL)
156
    {
157
        $this->options[$key] = $value;
158
159
        return $this;
160
    }
161
162
    /**
163
     * @param array $params
164
     */
165
    public function setParams($params)
166
    {
167
        $this->params = $params;
168
    }
169
170
    /**
171
     * @return array
172
     */
173
    public function getHeaders()
174
    {
175
        return $this->headers;
176
    }
177
178
    /**
179
     * @param array $headers
180
     */
181
    public function setHeaders($headers)
182
    {
183
        $this->headers = $headers;
184
    }
185
186
    /**
187
     * @param $header
188
     * @param null $content
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $content is correct as it would always require null to be passed?
Loading history...
189
     *
190
     * @return $this
191
     */
192
    public function addHeader($header, $content = NULL)
193
    {
194
        $this->headers[$header] = $content;
195
196
        return $this;
197
    }
198
199
    /**
200
     * @return string
201
     */
202
    public function getType()
203
    {
204
        return $this->type;
205
    }
206
207
    /**
208
     * @param string $type
209
     */
210
    public function setType($type)
211
    {
212
        $this->type = $type;
213
    }
214
215
    /**
216
     * @return Logger
217
     */
218
    public function getLog()
219
    {
220
        return $this->log;
221
    }
222
223
    /**
224
     * @param Logger $log
225
     */
226 2
    public function setLog($log)
227
    {
228 2
        $this->log = $log;
229 2
    }
230
231
    /**
232
     * @param bool $isJson
233
     */
234
    public function setIsJson($isJson = true) {
235
        $this->isJson = $isJson;
236
        if($isJson) {
237
            $this->setIsMultipart(false);
238
        }
239
    }
240
241
    /**
242
     * @return bool
243
     */
244
    public function getIsJson() {
245
        return $this->isJson;
246
    }
247
248
    /**
249
     * @param bool $isMultipart
250
     */
251
    public function setIsMultipart($isMultipart = true) {
252
        $this->isMultipart = $isMultipart;
253
        if($isMultipart) {
254
            $this->setIsJson(false);
255
        }
256
    }
257
258
    /**
259
     * @return bool
260
     */
261
    public function getIsMultipart() {
262
        return $this->isMultipart;
263
    }
264
265
    /**
266
     * Método que limpia el contexto de la llamada
267
     */
268 2
    private function clearContext()
269
    {
270 2
        $this->url = NULL;
271 2
        $this->params = array();
272 2
        $this->headers = array();
273 2
        Logger::log('Context service for ' . static::class . ' cleared!');
274 2
        $this->closeConnection();
275 2
    }
276
277
    /**
278
     *
279
     */
280 2
    public function init()
281
    {
282 2
        parent::init();
283 2
        $this->clearContext();
284 2
    }
285
286
    /**
287
     * Initialize CURL
288
     */
289 1
    private function initialize()
290
    {
291 1
        $this->closeConnection();
292 1
        $this->params = [];
293 1
        $this->con = curl_init($this->url);
0 ignored issues
show
Documentation Bug introduced by
It seems like curl_init($this->url) can also be of type false. However, the property $con 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...
294 1
    }
295
296
    /**
297
     * Generate auth header
298
     * @param string $secret
299
     * @param string $module
300
     */
301
    protected function addRequestToken($secret, $module = 'PSFS')
302
    {
303
        $this->addHeader('X-PSFS-SEC-TOKEN', SecurityHelper::generateToken($secret, $module));
304
    }
305
306
    /**
307
     * @param $user
308
     * @param $pass
309
     */
310
    protected function addAuthHeader($user, $pass) {
311
        $this->addOption(CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
312
        $this->addOption(CURLOPT_USERPWD, "$user:$pass");
313
    }
314
315
    protected function applyOptions() {
316
        if(count($this->options)) {
317
            curl_setopt_array($this->con, $this->options);
318
        }
319
    }
320
321
    protected function applyHeaders() {
322
        $headers = [];
323
        foreach($this->headers as $key => $value) {
324
            $headers[] = $key . ': ' . $value;
325
        }
326
        $headers[self::PSFS_TRACK_HEADER] = Logger::getUid();
327
        if(count($headers)) {
328
            curl_setopt($this->con, CURLOPT_HTTPHEADER, $headers);
329
        }
330
    }
331
332
    /**
333
     * @return int
334
     */
335
    private function parseServiceType() {
336
        if($this->getIsJson()) {
337
            return ServiceHelper::TYPE_JSON;
338
        }
339
        if($this->getIsMultipart()) {
340
            return ServiceHelper::TYPE_MULTIPART;
341
        }
342
        return ServiceHelper::TYPE_HTTP;
343
    }
344
345
    protected function setDefaults()
346
    {
347
        $serviceType = $this->parseServiceType();
348
        switch (strtoupper($this->type)) {
349
            case Request::VERB_GET:
350
            default:
351
                $this->addOption(CURLOPT_CUSTOMREQUEST, Request::VERB_GET);
352
                if(!empty($this->params)) {
353
                    $sep = false === strpos($this->getUrl(), '?') ? '?' : '';
354
                    $this->url = $this->url . $sep . http_build_query($this->params);
355
                }
356
                break;
357
            case Request::VERB_POST:
358
                $this->addOption(CURLOPT_CUSTOMREQUEST, Request::VERB_POST);
359
                $this->addOption(CURLOPT_POSTFIELDS, ServiceHelper::parseRawData($serviceType, $this->getParams()));
360
                break;
361
            case Request::VERB_DELETE:
362
                $this->addOption(CURLOPT_CUSTOMREQUEST, Request::VERB_DELETE);
363
                break;
364
            case Request::VERB_PUT:
365
                $this->addOption(CURLOPT_CUSTOMREQUEST, Request::VERB_PUT);
366
                $this->addOption(CURLOPT_POSTFIELDS, ServiceHelper::parseRawData($serviceType, $this->getParams()));
367
                break;
368
            case Request::VERB_PATCH:
369
                $this->addOption(CURLOPT_CUSTOMREQUEST, Request::VERB_PATCH);
370
                $this->addOption(CURLOPT_POSTFIELDS, ServiceHelper::parseRawData($serviceType, $this->getParams()));
371
                break;
372
        }
373
374
        $this->addOption(CURLOPT_RETURNTRANSFER, true);
375
        $this->addOption(CURLOPT_FOLLOWLOCATION, true);
376
        $this->addOption(CURLOPT_SSL_VERIFYHOST, false);
377
        $this->addOption(CURLOPT_SSL_VERIFYPEER, false);
378
    }
379
380
    public function callSrv()
381
    {
382
        $this->setDefaults();
383
        $this->applyOptions();
384
        $this->applyHeaders();
385
        $verbose = null;
386
        if('debug' === Config::getParam('log.level')) {
387
            curl_setopt($this->con, CURLOPT_VERBOSE, true);
388
            $verbose = fopen('php://temp', 'wb+');
389
            curl_setopt($this->con, CURLOPT_STDERR, $verbose);
390
        }
391
        $result = curl_exec($this->con);
392
        $this->setResult($this->isJson ? json_decode($result, true) : $result);
393
        if('debug' === Config::getParam('log.level')) {
394
            rewind($verbose);
0 ignored issues
show
Bug introduced by
It seems like $verbose can also be of type false; however, parameter $handle of rewind() 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

394
            rewind(/** @scrutinizer ignore-type */ $verbose);
Loading history...
395
            $verboseLog = stream_get_contents($verbose);
0 ignored issues
show
Bug introduced by
It seems like $verbose can also be of type false; however, parameter $handle of stream_get_contents() 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
            $verboseLog = stream_get_contents(/** @scrutinizer ignore-type */ $verbose);
Loading history...
396
            Logger::log($verboseLog, LOG_DEBUG, [
397
                'headers' => $this->getHeaders(),
398
                'options' => $this->getOptions(),
399
                'url' => $this->getUrl(),
400
            ]);
401
            $this->info['verbose'] = $verboseLog;
402
        }
403
        Logger::log($this->url . ' response: ', LOG_DEBUG, is_array($this->result) ? $this->result : [$this->result]);
404
        $this->info = array_merge($this->info, curl_getinfo($this->con));
405
    }
406
407
    /**
408
     * @return mixed
409
     */
410
    public function getCallInfo() {
411
        return $this->info;
412
    }
413
414
}
415