Passed
Push — master ( 33dcd4...7a8481 )
by Francis
06:54
created

REST::bearer_auth()   B

Complexity

Conditions 8
Paths 16

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 8
eloc 12
c 2
b 0
f 0
nc 16
nop 2
dl 0
loc 20
rs 8.4444
1
<?php
2
declare(strict_types=1);
3
defined('BASEPATH') OR exit('No direct script access allowed');
4
5
require_once('RESTAuth.php');
6
require_once('RESTResponse.php');
7
require_once('RESTExceptions.php');
8
9
class REST
10
{
11
  /**
12
   * [private description]
13
   * @var [type]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
14
   */
15
  private $ci;
16
17
  /**
18
   * [private description]
19
   * @var [type]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
20
   */
21
  private $api_key_limit_column;
22
23
  /**
24
   * [private description]
25
   * @var [type]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
26
   */
27
  private $api_key_column;
28
29
  /**
30
   * [private description]
31
   * @var [type]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
32
   */
33
  private $per_hour;
34
35
  /**
36
   * [private description]
37
   * @var [type]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
38
   */
39
  private $ip_per_hour;
40
41
  /**
42
   * [private description]
43
   * @var [type]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
44
   */
45
  private $show_header;
46
47
  /**
48
   * [private description]
49
   * @var [type]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
50
   */
51
  private $whitelist;
52
53
  /**
54
   * [private description]
55
   * @var [type]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
56
   */
57
  private $checked_rate_limit = false;
58
59
  /**
60
   * [private description]
61
   * @var [type]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
62
   */
63
  private $header_prefix;
64
65
  /**
66
   * [private description]
67
   * @var [type]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
68
   */
69
  private $limit_api;
70
71
  /**
72
   * [public description]
73
   * @var [type]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
74
   */
75
  public  $userId;
76
77
  /**
78
   * [public description]
79
   * @var [type]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
80
   */
81
  public $apiKey;
82
83
  /**
84
   * [public description]
85
   * @var [type]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
86
   */
87
  public  $apiKeyHeader;
88
89
  /**
90
   * [public description]
91
   * @var [type]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
92
   */
93
  public $token;
94
95
  /**
96
   * [public description]
97
   * @var [type]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
98
   */
99
  public $allowedIps;
100
101
  /**
102
   * [public description]
103
   * @var [type]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
104
   */
105
  public $config;
106
107
  /**
108
   * [public description]
109
   * @var [type]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
110
   */
111
  public $authPreempted = false;
112
113
  /**
114
   * [PACKAGE description]
115
   * @var string
116
   */
117
  const PACKAGE = "francis94c/ci-rest";
118
119
  /**
120
   * [RATE_LIMIT description]
121
   * @var string
122
   */
123
  const RATE_LIMIT = "RateLimit";
124
125
  /**
126
   * [AUTH_GRAVITY description]
127
   * @var integer
128
   */
129
  const AUTH_GRAVITY = 0b100;
130
  const AUTH_PASSIVE = 0b010;
131
  const AUTH_FINAL   = 0b001;
132
133
  /**
134
   * [__construct This is the part of the code that takes care of all
135
   * authentiations. allowing you to focus on building wonderful things at REST.
136
   * pun intended ;-)]
137
   * @param array|null $params Initialization parameters from the Slint system.
138
   *                           There's no use for this arg yet.
139
   */
140
  function __construct(?array $params=null)
141
  {
142
    $this->ci =& get_instance();
0 ignored issues
show
Bug introduced by
The function get_instance was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

142
    $this->ci =& /** @scrutinizer ignore-call */ get_instance();
Loading history...
143
144
    if ($this->ci->input->is_cli_request()) return;
145
146
    // Load Config If Exists.
147
    //$this->ci->config->load('rest', true, true);
148
    if (is_file(APPPATH . 'config/rest.php')) {
0 ignored issues
show
Bug introduced by
The constant APPPATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
149
      include APPPATH . 'config/rest.php';
150
    }
151
152
    $this->config = $config;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $config seems to be never defined.
Loading history...
153
154
    // Load Database.
155
    $this->ci->load->database();
156
157
    // load URL Helper
158
    $this->ci->load->helper('url');
159
160
    // Load REST Helper.
161
    $this->ci->load->splint(self::PACKAGE, '%rest');
162
163
    // Load Model.
164
    $this->ci->load->splint(self::PACKAGE, '*RESTModel', 'rest_model');
165
    $this->rest_model =& $this->ci->rest_model;
0 ignored issues
show
Bug Best Practice introduced by
The property rest_model does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
166
167
    $this->rest_model->init([
168
      'users_table'           => $config['basic_auth']['users_table'] ?? null,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $config seems to never exist and therefore isset should always be false.
Loading history...
169
      'users_id_column'       => $config['basic_auth']['id_column'] ?? null,
170
      'users_username_column' => $config['basic_auth']['username_column'] ?? null,
171
      'users_email_column'    => $config['basic_auth']['email_column'] ?? null,
172
      'users_password_column' => $config['basic_auth']['password_column'] ?? null,
173
      'api_key_table'         => $config['api_key_auth']['api_key_table'] ?? null,
174
      'api_key_column'        => $config['api_key_auth']['api_key_column'] ?? null,
175
      'api_key_limit_column'  => $config['api_key_auth']['api_key_limit_column'] ?? null
176
    ]);
177
178
    // Load Variable(s) from Config.
179
    $this->allowedIps = $config['allowed_ips'] ?? ['127.0.0.1', '[::1]'];
180
    $this->apiKeyHeader = $config['api_key_header'] ?? 'X-API-KEY';
181
    $this->api_key_limit_column = $config['api_key_auth']['api_key_limit_column'] ?? null;
182
    $this->api_key_column = $config['api_key_auth']['api_key_column'] ?? null;
183
    $this->limit_api = $config['api_limiter']['api_limiter'] ?? false;
184
    $this->per_hour = $config['api_limiter']['per_hour'] ?? 100;
185
    $this->ip_per_hour = $config['api_limiter']['ip_per_hour'] ?? 50;
186
    $this->show_header = $config['api_limiter']['show_header'] ?? null;
187
    $this->whitelist = $config['api_limiter']['whitelist'] ?? [];
188
    $this->header_prefix = $config['api_limiter']['header_prefix'] ?? 'X-RateLimit-';
189
190
    // Limit Only?
191
    //if ($this->config['api_limiter']['api_limit_only'] ?? false) {
192
      //return;
193
    //}
194
195
    // Authenticate
196
    $this->authenticate();
197
198
    // Generic Rate Limiter.
199
    if ($this->limit_api && !$this->checked_rate_limit &&
200
    ($config['api_limiter']['limit_by_ip'] ?? false)) {
201
      $this->api_rest_limit_by_ip_address();
202
    }
203
204
    log_message('debug', 'REST Request Authenticated and REST Library Initialized.');
0 ignored issues
show
Bug introduced by
The function log_message was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

204
    /** @scrutinizer ignore-call */ 
205
    log_message('debug', 'REST Request Authenticated and REST Library Initialized.');
Loading history...
205
  }
206
207
  /**
208
   * [authenticate description]
209
   * @date 2020-01-30
210
   */
211
  private function authenticate():void
212
  {
213
    $auths = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $auths is dead and can be removed.
Loading history...
214
    $auths = $this->config['auth'] ?? null;
215
    if ($auths) $auths = is_array($auths) ? $auths : [$auths];
216
217
    if (!$auths) return; // No authentication(s) to carry out.
218
219
    /**
220
     * $this->process_auth() terminates the script if authentication fails
221
     * It will call the callable in the rest.php config file under
222
     * response_callbacks which matches the necesarry RESTResponse constant
223
     * before exiting. Which callable is called in any situation is documented
224
     * in README.md
225
     */
226
227
    foreach ($auths as $key => $auth) {
228
      if ($this->authPreempted) break;
229
      if (is_numeric($key)) {
230
        $this->process_auth($auth, self::AUTH_GRAVITY);
231
      } else {
232
        $this->process_auth($key, $auth);
233
      }
234
    }
235
  }
236
237
  /**
238
   * [process_auth description]
239
   * @date  2020-04-07
240
   * @param string     $auth  [description]
241
   * @param int        $flags [description]
242
   */
243
  private function process_auth(string &$auth, int $flags):void
244
  {
245
    switch ($auth) {
246
      case RESTAuth::IP: $this->ip_auth($flags); break;
247
      case RESTAuth::BASIC: $this->basic_auth($flags); break;
248
      case RESTAuth::API_KEY: $this->api_key_auth($flags); break;
249
      case RESTAuth::OAUTH2: $this->bearer_auth(RESTAuth::OAUTH2, $flags); break;
250
      case RESTAuth::BEARER: $this->bearer_auth(RESTAuth::BEARER, $flags); break;
251
      case RESTAuth::SECRET: $this->bearer_auth(RESTAuth::SECRET, $flags); break;
252
      default: $this->custom_auth($auth, $flags);
0 ignored issues
show
Unused Code introduced by
The call to REST::custom_auth() has too many arguments starting with $flags. ( Ignorable by Annotation )

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

252
      default: $this->/** @scrutinizer ignore-call */ custom_auth($auth, $flags);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
253
    }
254
  }
255
256
  /**
257
   * [auth_proceed description]
258
   * @date   2020-04-07
259
   * @param  bool       $success [description]
260
   * @param  int        $flags   [description]
261
   * @return bool                [description]
262
   */
263
  private function auth_proceed(bool $success, int $flags):bool
264
  {
265
    if ($flags & self::AUTH_GRAVITY) return $success;
266
    if ($success) {
267
      if ($flags & self::AUTH_FINAL) {
268
        $this->authPreempted = true;
269
        return true;
270
      }
0 ignored issues
show
Bug Best Practice introduced by
The function implicitly returns null when the if condition on line 267 is false. This is incompatible with the type-hinted return boolean. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
271
    } else {
272
      return $flags & self::AUTH_PASSIVE ? true : false;
273
    }
274
  }
275
276
  /**
277
   * [ip_auth description]
278
   * @date  2020-04-07
279
   * @param int        $flags [description]
280
   */
281
  private function ip_auth(int $flags):void
282
  {
283
    if (!$this->auth_proceed(in_array($this->ci->input->ip_address(), $this->allowedIps), $flags)) {
284
      $this->handle_response(RESTResponse::UN_AUTHORIZED, RESTAuth::IP); // Exits.
285
    }
286
  }
287
288
  /**
289
   * [bearer_auth description]
290
   * @date  2020-04-07
291
   * @param string     $auth  [description]
292
   * @param int        $flags [description]
293
   */
294
  private function bearer_auth(string $auth, int $flags):void
295
  {
296
    $authorization = $this->get_authorization_header();
297
    $shouldProceed = $this->auth_proceed(false, $flags);
298
    if ($authorization == null || substr_count($authorization, ' ') != 1 && !$shouldProceed) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $authorization of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
299
      $this->handle_response(RESTResponse::BAD_REQUEST, $auth, 'Bad Request'); // Exits.
300
    }
301
    $token = explode(" ", $authorization);
302
    if ($token[0] != $auth && !$shouldProceed) {
303
      $this->handle_response(RESTResponse::BAD_REQUEST, $auth, 'Bad Request'); // Exits.
304
    }
305
    $this->token = $token[1];
306
    // Call Up Custom Implemented Bearer/Token Authorization.
307
    // Callback Check.
308
    if (!isset($this->config['auth_callbacks'][$auth])) {
309
      $this->handle_response(RESTResponse::NOT_IMPLEMENTED, $auth); // Exits.
310
    }
311
    // Authorization.
312
    if (!$this->auth_proceed($this->config['auth_callbacks'][$auth]($this, $this->token), $flags)) {
313
      $this->handle_response(RESTResponse::UN_AUTHORIZED, $auth); // Exits.
314
    }
315
  }
316
317
  /**
318
   * [basic_auth description]
319
   * @date  2020-04-07
320
   * @param int        $flags [description]
321
   */
322
  private function basic_auth(int $flags):void
323
  {
324
    $username = $_SERVER['PHP_AUTH_USER'] ?? null;
325
    $password = $_SERVER['PHP_AUTH_PW'] ?? null;
326
    if (!$this->auth_proceed(!$username || !$password, $flags)) $this->handle_response(RESTResponse::BAD_REQUEST, RESTAuth::BASIC); // Exits.
327
    if (!$this->auth_proceed($this->rest_model->basicAuth($this, $username, $password), $flags)) $this->handle_response(RESTResponse::UN_AUTHORIZED, RESTAuth::BASIC); // Exits.
328
  }
329
  /**
330
   * [api_key_auth description]
331
   */
332
  private function api_key_auth(int $flags=self::AUTH_GRAVITY):void
333
  {
334
    if (uri_string() == '')  return;
0 ignored issues
show
Bug introduced by
The function uri_string was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

334
    if (/** @scrutinizer ignore-call */ uri_string() == '')  return;
Loading history...
335
    $shouldProceed = $this->auth_proceed(false, $flags);
336
337
    if (!$this->ci->input->get_request_header($this->apiKeyHeader, true) && !$shouldProceed) {
338
    // if (!isset($_SERVER['HTTP_' . str_replace("-", "_", $this->apiKeyHeader)])) {
339
      $this->handle_response(RESTResponse::BAD_REQUEST, RESTAuth::API_KEY); // Exits.
340
    }
341
342
    $apiKey = $this->rest_model->getAPIKeyData(
343
      $this->ci->input->get_request_header($this->apiKeyHeader, true)
344
    );
345
346
    if ($apiKey == null && !$shouldProceed) {
347
      $this->handle_response(RESTResponse::UN_AUTHORIZED, RESTAuth::API_KEY); // Exits.
348
    }
349
350
    $this->apiKey = $apiKey;
351
352
    if (!$this->auth_proceed(true, $flags)) return;
353
354
    // API KEY Auth Passed Above.
355
    if ($this->limit_api && $this->api_key_limit_column != null && $apiKey->{$this->api_key_limit_column} == 1) {
356
      // Trunctate Rate Limit Data.
357
      $this->rest_model->truncateRatelimitData();
358
      // Check Whitelist.
359
      if (in_array($this->ci->input->ip_address(), $this->whitelist)) {
360
        $this->checked_rate_limit = true; // Ignore Limit By IP.
361
        return;
362
      }
363
      // Should we acyually Limit?
364
      if ($this->per_hour > 0) {
365
        $client = hash('md5', $this->ci->input->ip_address() . "%" . $apiKey->{$this->api_key_column});
366
        $limitData = $this->rest_model->getLimitData($client, '_api_keyed_user');
367
        if ($limitData == null) {
368
          $limitData = [];
369
          $limitData['count'] = 0;
370
          $limitData['reset_epoch'] = gmdate('d M Y H:i:s', time() + (60 * 60));
371
          $limitData['start'] = date('d M Y H:i:s');
372
        }
373
        if ($this->per_hour - $limitData['count'] > 0) {
374
          if (!$this->rest_model->insertLimitData($client, '_api_keyed_user')) {
375
            $this->handle_response(RESTResponse::INTERNAL_SERVER_ERROR, self::RATE_LIMIT); // Exits.
376
          }
377
          ++$limitData['count'];
378
          if ($this->show_header) {
379
            header($this->header_prefix.'Limit: '.$this->per_hour);
380
            header($this->header_prefix.'Remaining: '.($this->per_hour - $limitData['count']));
381
            header($this->header_prefix.'Reset: '.strtotime($limitData['reset_epoch']));
382
          }
383
        } else {
384
          header('Retry-After: '.(strtotime($limitData['reset_epoch']) - strtotime(gmdate('d M Y H:i:s'))));
385
          $this->handle_response(RESTResponse::TOO_MANY_REQUESTS, self::RATE_LIMIT); // Exits.
386
        }
387
      }
388
    }
389
    $this->checked_rate_limit = true; // Ignore Limit By IP.
390
  }
391
392
  /**
393
   * [api_rest_limit_by_ip_address description]
394
   * TODO: Implement.
395
   */
396
  private function api_rest_limit_by_ip_address():void
397
  {
398
    // Trunctate Rate Limit Data.
399
    $this->rest_model->truncateRatelimitData();
400
    // Check Whitelist.
401
    if (in_array($this->ci->input->ip_address(), $this->whitelist)) return;
402
    // Should we acyually Limit?
403
    if ($this->ip_per_hour > 0) {
404
      $client = hash('md5', $this->ci->input->ip_address());
405
      $limitData = $this->rest_model->getLimitData($client, '_ip_address');
406
      if ($limitData == null) {
407
        $limitData = [];
408
        $limitData['count'] = 0;
409
        $limitData['reset_epoch'] = gmdate('d M Y H:i:s', time() + (60 * 60));
410
        $limitData['start'] = date('d M Y H:i:s');
411
      }
412
      if ($this->ip_per_hour - $limitData['count'] > 0) {
413
        if (!$this->rest_model->insertLimitData($client, '_ip_address')) {
414
          $this->handle_response(RESTResponse::INTERNAL_SERVER_ERROR, self::RATE_LIMIT); // Exits.
415
        }
416
        ++$limitData['count'];
417
        if ($this->show_header) {
418
          header($this->header_prefix.'Limit: '.$this->ip_per_hour);
419
          header($this->header_prefix.'Remaining: '.($this->ip_per_hour - $limitData['count']));
420
          header($this->header_prefix.'Reset: '.strtotime($limitData['reset_epoch']));
421
        }
422
      } else {
423
        header('Retry-After: '.(strtotime($limitData['reset_epoch']) - strtotime(gmdate('d M Y H:i:s'))));
424
        $this->handle_response(RESTResponse::TOO_MANY_REQUESTS, self::RATE_LIMIT); // Exits.
425
      }
426
    }
427
  }
428
  /**
429
   * [custom_auth description]
430
   * @param string $auth [description]
431
   */
432
  private function custom_auth(string &$auth):void
433
  {
434
    // Header Check.
435
    if (!isset($_SERVER[$auth])) {
436
      $this->handle_response(RESTResponse::BAD_REQUEST, $auth);
437
    }
438
    // Callback Check.
439
    if (!isset($this->config['auth_callbacks'][$auth])) {
440
      $this->handle_response(RESTResponse::NOT_IMPLEMENTED, $auth); // Exits.
441
    }
442
    // Authentication.
443
    if (!$this->config['auth_callbacks'][$auth]($this, $this->ci->security->xss_clean($_SERVER[$auth]))) {
444
      $this->handle_response(RESTResponse::UN_AUTHORIZED, $auth); // Exits.
445
    }
446
  }
447
  /**
448
   * [get_authorization_header description]
449
   * @return [type] [description]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
450
   */
451
  private function get_authorization_header():?string
452
  {
453
    if (isset($_SERVER['Authorization'])) {
454
      return trim($_SERVER["Authorization"]);
455
    } else if (isset($_SERVER['HTTP_AUTHORIZATION'])) { //Nginx or fast CGI
456
      return trim($_SERVER["HTTP_AUTHORIZATION"]);
457
    } elseif (function_exists('apache_request_headers')) {
458
      $requestHeaders = apache_request_headers();
459
460
      // Avoid Surprises.
461
      $requestHeaders = array_combine(array_map('ucwords', array_keys($requestHeaders)), array_values($requestHeaders));
0 ignored issues
show
Bug introduced by
It seems like $requestHeaders can also be of type false; however, parameter $input of array_keys() does only seem to accept array, 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

461
      $requestHeaders = array_combine(array_map('ucwords', array_keys(/** @scrutinizer ignore-type */ $requestHeaders)), array_values($requestHeaders));
Loading history...
Bug introduced by
It seems like $requestHeaders can also be of type false; however, parameter $input of array_values() does only seem to accept array, 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

461
      $requestHeaders = array_combine(array_map('ucwords', array_keys($requestHeaders)), array_values(/** @scrutinizer ignore-type */ $requestHeaders));
Loading history...
462
463
      if (isset($requestHeaders['Authorization'])) {
464
        return trim($requestHeaders['Authorization']);
465
      }
466
    }
467
    return null;
468
  }
469
470
  /**
471
   * [handle_response description]
472
   * @param int $code [description]
473
   */
474
  private function handle_response(int $code, $auth=null, ?string $errorReason=null):void
475
  {
476
    http_response_code($code);
477
    header("Content-Type: application/json");
478
    if (isset($this->config['response_callbacks'][$code])) {
479
      $this->config['response_callbacks'][$code]($auth, $errorReason);
480
    }
481
    if (ENVIRONMENT != 'testing') exit($code);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
Bug introduced by
The constant ENVIRONMENT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
482
    throw new Exception("Error $code in $auth", $code);
483
  }
484
}
485
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
486