DataBuilder::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 42
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 37
dl 0
loc 42
rs 9.328
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php namespace Rollbar;
2
3
use Rollbar\Payload\Context;
4
use Rollbar\Payload\Message;
5
use Rollbar\Payload\Body;
6
use Rollbar\Payload\Level;
7
use Rollbar\Payload\Person;
8
use Rollbar\Payload\Server;
9
use Rollbar\Payload\Request;
10
use Rollbar\Payload\Data;
11
use Rollbar\Payload\Trace;
12
use Rollbar\Payload\Frame;
13
use Rollbar\Payload\TraceChain;
14
use Rollbar\Payload\ExceptionInfo;
15
use Rollbar\Rollbar;
16
use Rollbar\Exceptions\PersonFuncException;
0 ignored issues
show
Bug introduced by
The type Rollbar\Exceptions\PersonFuncException 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...
17
18
class DataBuilder implements DataBuilderInterface
19
{
20
    const ANONYMIZE_IP = 'anonymize';
21
    
22
    protected static $defaults;
23
24
    protected $environment;
25
    protected $messageLevel;
26
    protected $exceptionLevel;
27
    protected $psrLevels;
28
    protected $errorLevels;
29
    protected $codeVersion;
30
    protected $platform;
31
    protected $framework;
32
    protected $context;
33
    protected $requestParams;
34
    protected $requestBody;
35
    protected $requestExtras;
36
    protected $host;
37
    protected $person;
38
    protected $personFunc;
39
    protected $serverRoot;
40
    protected $serverBranch;
41
    protected $serverCodeVersion;
42
    protected $serverExtras;
43
    protected $custom;
44
    protected $customDataMethod;
45
    protected $fingerprint;
46
    protected $title;
47
    protected $notifier;
48
    protected $baseException;
49
    protected $includeCodeContext;
50
    protected $includeExcCodeContext;
51
    protected $sendMessageTrace;
52
    protected $rawRequestBody;
53
    protected $localVarsDump;
54
    protected $captureErrorStacktraces;
55
    protected $captureIP;
56
    protected $captureEmail;
57
    protected $captureUsername;
58
    
59
    /**
60
     * @var LevelFactory
61
     */
62
    protected $levelFactory;
63
    
64
    /**
65
     * @var Utilities
66
     */
67
    protected $utilities;
68
69
    public function __construct($config)
70
    {
71
        self::$defaults = Defaults::get();
72
        
73
        $this->setUtilities($config);
74
        
75
        $this->setEnvironment($config);
76
77
        $this->setRawRequestBody($config);
78
        $this->setDefaultMessageLevel($config);
79
        $this->setDefaultExceptionLevel($config);
80
        $this->setDefaultPsrLevels($config);
81
        $this->setErrorLevels($config);
82
        $this->setCodeVersion($config);
83
        $this->setPlatform($config);
84
        $this->setFramework($config);
85
        $this->setContext($config);
86
        $this->setRequestParams($config);
87
        $this->setRequestBody($config);
88
        $this->setRequestExtras($config);
89
        $this->setHost($config);
90
        $this->setPerson($config);
91
        $this->setPersonFunc($config);
92
        $this->setServerRoot($config);
93
        $this->setServerBranch($config);
94
        $this->setServerCodeVersion($config);
95
        $this->setServerExtras($config);
96
        $this->setCustom($config);
97
        $this->setFingerprint($config);
98
        $this->setTitle($config);
99
        $this->setNotifier($config);
100
        $this->setBaseException($config);
101
        $this->setIncludeCodeContext($config);
102
        $this->setIncludeExcCodeContext($config);
103
        $this->setSendMessageTrace($config);
104
        $this->setLocalVarsDump($config);
105
        $this->setCaptureErrorStacktraces($config);
106
        $this->setLevelFactory($config);
107
        $this->setCaptureEmail($config);
108
        $this->setCaptureUsername($config);
109
        $this->setCaptureIP($config);
110
        $this->setCustomDataMethod($config);
111
    }
112
113
    protected function setCaptureIP($config)
114
    {
115
        $fromConfig = isset($config['capture_ip']) ? $config['capture_ip'] : null;
116
        $this->captureIP = self::$defaults->captureIP($fromConfig);
117
    }
118
    
119
    protected function setCaptureEmail($config)
120
    {
121
        $fromConfig = isset($config['capture_email']) ? $config['capture_email'] : null;
122
        $this->captureEmail = self::$defaults->captureEmail($fromConfig);
123
    }
124
    
125
    protected function setCaptureUsername($config)
126
    {
127
        $fromConfig = isset($config['capture_username']) ? $config['capture_username'] : null;
128
        $this->captureUsername = self::$defaults->captureUsername($fromConfig);
129
    }
130
131
    protected function setEnvironment($config)
132
    {
133
        $fromConfig = isset($config['environment']) ? $config['environment'] : self::$defaults->get()->environment();
134
        $this->utilities->validateString($fromConfig, "config['environment']", null, false);
135
        $this->environment = $fromConfig;
136
    }
137
138
    protected function setDefaultMessageLevel($config)
139
    {
140
        $fromConfig = isset($config['messageLevel']) ? $config['messageLevel'] : null;
141
        $this->messageLevel = self::$defaults->messageLevel($fromConfig);
142
    }
143
144
    protected function setDefaultExceptionLevel($config)
145
    {
146
        $fromConfig = isset($config['exceptionLevel']) ? $config['exceptionLevel'] : null;
147
        $this->exceptionLevel = self::$defaults->exceptionLevel($fromConfig);
148
    }
149
150
    protected function setDefaultPsrLevels($config)
151
    {
152
        $fromConfig = isset($config['psrLevels']) ? $config['psrLevels'] : null;
153
        $this->psrLevels = self::$defaults->psrLevels($fromConfig);
154
    }
155
156
    protected function setErrorLevels($config)
157
    {
158
        $fromConfig = isset($config['errorLevels']) ? $config['errorLevels'] : null;
159
        $this->errorLevels = self::$defaults->errorLevels($fromConfig);
160
    }
161
162
    protected function setSendMessageTrace($config)
163
    {
164
        $fromConfig = isset($config['send_message_trace']) ? $config['send_message_trace'] : null;
165
        $this->sendMessageTrace = self::$defaults->sendMessageTrace($fromConfig);
166
    }
167
    
168
    protected function setRawRequestBody($config)
169
    {
170
        $fromConfig = isset($config['include_raw_request_body']) ? $config['include_raw_request_body'] : null;
171
        $this->rawRequestBody = self::$defaults->rawRequestBody($fromConfig);
172
    }
173
174
    protected function setLocalVarsDump($config)
175
    {
176
        $fromConfig = isset($config['local_vars_dump']) ? $config['local_vars_dump'] : null;
177
        $this->localVarsDump = self::$defaults->localVarsDump($fromConfig);
178
    }
179
    
180
    protected function setCaptureErrorStacktraces($config)
181
    {
182
        $fromConfig = isset($config['capture_error_stacktraces']) ? $config['capture_error_stacktraces'] : null;
183
        $this->captureErrorStacktraces = self::$defaults->captureErrorStacktraces($fromConfig);
184
    }
185
186
    protected function setCodeVersion($config)
187
    {
188
        $fromConfig = isset($config['codeVersion']) ? $config['codeVersion'] : null;
189
        if (!isset($fromConfig)) {
190
            $fromConfig = isset($config['code_version']) ? $config['code_version'] : null;
191
        }
192
        $this->codeVersion = self::$defaults->codeVersion($fromConfig);
193
    }
194
195
    protected function setPlatform($config)
196
    {
197
        $fromConfig = isset($config['platform']) ? $config['platform'] : null;
198
        $this->platform = self::$defaults->platform($fromConfig);
199
    }
200
201
    protected function setFramework($config)
202
    {
203
        $this->framework = isset($config['framework']) ? $config['framework'] : null;
204
    }
205
206
    protected function setContext($config)
207
    {
208
        $this->context = isset($config['context']) ? $config['context'] : null;
209
    }
210
211
    protected function setRequestParams($config)
212
    {
213
        $this->requestParams = isset($config['requestParams']) ? $config['requestParams'] : null;
214
    }
215
216
    /*
217
     * @SuppressWarnings(PHPMD.Superglobals)
218
     */
219
    protected function setRequestBody($config)
220
    {
221
        
222
        $this->requestBody = isset($config['requestBody']) ? $config['requestBody'] : null;
223
        
224
        if (!$this->requestBody && $this->rawRequestBody) {
225
            $this->requestBody = file_get_contents("php://input");
226
            if (version_compare(PHP_VERSION, '5.6.0') < 0) {
227
                $_SERVER['php://input'] = $this->requestBody;
228
            }
229
        }
230
    }
231
232
    protected function setRequestExtras($config)
233
    {
234
        $this->requestExtras = isset($config["requestExtras"]) ? $config["requestExtras"] : null;
235
    }
236
237
    protected function setPerson($config)
238
    {
239
        $this->person = isset($config['person']) ? $config['person'] : null;
240
    }
241
242
    protected function setPersonFunc($config)
243
    {
244
        $this->personFunc = isset($config['person_fn']) ? $config['person_fn'] : null;
245
    }
246
247
    protected function setServerRoot($config)
248
    {
249
        $fromConfig = isset($config['serverRoot']) ? $config['serverRoot'] : null;
250
        if (!isset($fromConfig)) {
251
            $fromConfig = isset($config['root']) ? $config['root'] : null;
252
        }
253
        $this->serverRoot = self::$defaults->serverRoot($fromConfig);
254
    }
255
256
    protected function setServerBranch($config)
257
    {
258
        $fromConfig = isset($config['serverBranch']) ? $config['serverBranch'] : null;
259
        if (!isset($fromConfig)) {
260
            $fromConfig = isset($config['branch']) ? $config['branch'] : null;
261
        }
262
        $allowExec = isset($config['allow_exec']) ? $config['allow_exec'] : null;
263
        if (!isset($allowExec)) {
264
            $allowExec = true;
265
        }
266
        $this->serverBranch = self::$defaults->gitBranch($fromConfig, $allowExec);
267
    }
268
269
    protected function setServerCodeVersion($config)
270
    {
271
        $this->serverCodeVersion = isset($config['serverCodeVersion']) ? $config['serverCodeVersion'] : null;
272
    }
273
274
    protected function setServerExtras($config)
275
    {
276
        $this->serverExtras = isset($config['serverExtras']) ? $config['serverExtras'] : null;
277
    }
278
279
    public function setCustom($config)
280
    {
281
        $this->custom = isset($config['custom']) ? $config['custom'] : \Rollbar\Defaults::get()->custom();
282
    }
283
    
284
    public function setCustomDataMethod($config)
285
    {
286
        $this->customDataMethod = isset($config['custom_data_method']) ?
287
            $config['custom_data_method'] :
288
            \Rollbar\Defaults::get()->customDataMethod();
289
    }
290
291
    protected function setFingerprint($config)
292
    {
293
        $this->fingerprint = isset($config['fingerprint']) ? $config['fingerprint'] : null;
294
    }
295
296
    protected function setTitle($config)
297
    {
298
        $this->title = isset($config['title']) ? $config['title'] : null;
299
    }
300
301
    protected function setNotifier($config)
302
    {
303
        $fromConfig = isset($config['notifier']) ? $config['notifier'] : null;
304
        $this->notifier = self::$defaults->notifier($fromConfig);
305
    }
306
307
    protected function setBaseException($config)
308
    {
309
        $fromConfig = isset($config['baseException']) ? $config['baseException'] : null;
310
        $this->baseException = self::$defaults->baseException($fromConfig);
311
    }
312
313
    protected function setIncludeCodeContext($config)
314
    {
315
        $fromConfig = isset($config['include_error_code_context']) ? $config['include_error_code_context'] : null;
316
        $this->includeCodeContext = self::$defaults->includeCodeContext($fromConfig);
317
    }
318
319
    protected function setIncludeExcCodeContext($config)
320
    {
321
        $fromConfig =
322
            isset($config['include_exception_code_context']) ? $config['include_exception_code_context'] : null;
323
        $this->includeExcCodeContext = self::$defaults->includeExcCodeContext($fromConfig);
324
    }
325
    
326
    protected function setLevelFactory($config)
327
    {
328
        $this->levelFactory = isset($config['levelFactory']) ? $config['levelFactory'] : null;
329
        if (!$this->levelFactory) {
330
            throw new \InvalidArgumentException(
331
                'Missing dependency: LevelFactory not provided to the DataBuilder.'
332
            );
333
        }
334
    }
335
    
336
    protected function setUtilities($config)
337
    {
338
        $this->utilities = isset($config['utilities']) ? $config['utilities'] : null;
339
        if (!$this->utilities) {
340
            throw new \InvalidArgumentException(
341
                'Missing dependency: Utilities not provided to the DataBuilder.'
342
            );
343
        }
344
    }
345
346
    protected function setHost($config)
347
    {
348
        $this->host = isset($config['host']) ? $config['host'] : self::$defaults->host();
349
    }
350
351
    /**
352
     * @param string $level
353
     * @param \Exception | \Throwable | string $toLog
354
     * @param $context
355
     * @return Data
356
     */
357
    public function makeData($level, $toLog, $context)
358
    {
359
        $env = $this->getEnvironment();
360
        $body = $this->getBody($toLog, $context);
361
        $data = new Data($env, $body);
362
        $data->setLevel($this->getLevel($level, $toLog))
363
            ->setTimestamp($this->getTimestamp())
364
            ->setCodeVersion($this->getCodeVersion())
365
            ->setPlatform($this->getPlatform())
366
            ->setLanguage($this->getLanguage())
367
            ->setFramework($this->getFramework())
368
            ->setContext($this->getContext())
369
            ->setRequest($this->getRequest())
370
            ->setPerson($this->getPerson())
371
            ->setServer($this->getServer())
372
            ->setCustom($this->getCustomForPayload($toLog, $context))
373
            ->setFingerprint($this->getFingerprint($context))
374
            ->setTitle($this->getTitle())
375
            ->setUuid($this->getUuid())
376
            ->setNotifier($this->getNotifier());
377
        return $data;
378
    }
379
380
    protected function getEnvironment()
381
    {
382
        return $this->environment;
383
    }
384
385
    protected function getBody($toLog, $context)
386
    {
387
        $baseException = $this->getBaseException();
388
        if ($toLog instanceof ErrorWrapper) {
389
            $content = $this->getErrorTrace($toLog);
390
        } elseif ($toLog instanceof $baseException) {
391
            $content = $this->getExceptionTrace($toLog);
392
        } else {
393
            $content = $this->getMessage($toLog, $context);
394
        }
395
        return new Body($content);
396
    }
397
398
    public function getErrorTrace(ErrorWrapper $error)
399
    {
400
        return $this->makeTrace($error, $this->includeCodeContext, $error->getClassName());
401
    }
402
403
    /**
404
     * @param \Throwable|\Exception $exc
405
     * @return Trace|TraceChain
406
     */
407
    public function getExceptionTrace($exc)
408
    {
409
        $chain = array();
410
        $chain[] = $this->makeTrace($exc, $this->includeExcCodeContext);
411
412
        $previous = $exc->getPrevious();
413
414
        $baseException = $this->getBaseException();
415
        while ($previous instanceof $baseException) {
416
            $chain[] = $this->makeTrace($previous, $this->includeExcCodeContext);
417
            if ($previous->getPrevious() === $previous) {
418
                break;
419
            }
420
            $previous = $previous->getPrevious();
421
        }
422
423
        if (count($chain) > 1) {
424
            return new TraceChain($chain);
425
        }
426
427
        return $chain[0];
428
    }
429
430
    /**
431
     * @param \Throwable|\Exception $exception
432
     * @param Boolean $includeContext whether or not to include context
433
     * @param string $classOverride
434
     * @return Trace
435
     */
436
    public function makeTrace($exception, $includeContext, $classOverride = null)
437
    {
438
        if ($this->captureErrorStacktraces) {
439
            $frames = $this->makeFrames($exception, $includeContext);
440
        } else {
441
            $frames = array();
442
        }
443
        
444
        $excInfo = new ExceptionInfo(
445
            $classOverride ?: get_class($exception),
446
            $exception->getMessage()
447
        );
448
        return new Trace($frames, $excInfo);
449
    }
450
451
    public function makeFrames($exception, $includeContext)
452
    {
453
        $frames = array();
454
        
455
        foreach ($this->getTrace($exception) as $frameInfo) {
456
            $filename = isset($frameInfo['file']) ? $frameInfo['file'] : null;
457
            $lineno = isset($frameInfo['line']) ? $frameInfo['line'] : null;
458
            $method = isset($frameInfo['function']) ? $frameInfo['function'] : null;
459
            if (isset($frameInfo['class'])) {
460
                $method = $frameInfo['class'] . "::" . $method;
461
            }
462
            $args = isset($frameInfo['args']) ? $frameInfo['args'] : null;
463
464
            $frame = new Frame($filename);
465
            $frame->setLineno($lineno)
466
                ->setMethod($method);
467
                
468
            if ($this->localVarsDump && $args !== null) {
469
                $frame->setArgs($args);
470
            }
471
472
            if ($includeContext) {
473
                $this->addCodeContextToFrame($frame, $filename, $lineno);
474
            }
475
476
            $frames[] = $frame;
477
        }
478
        
479
        $frames = array_reverse($frames);
480
481
        return $frames;
482
    }
483
484
    private function addCodeContextToFrame(Frame $frame, $filename, $line)
485
    {
486
        if (!file_exists($filename)) {
487
            return;
488
        }
489
490
        $source = $this->getSourceLines($filename);
491
492
        $total = count($source);
493
        $line = max($line - 1, 0);
494
        $frame->setCode($source[$line]);
495
        $offset = 6;
496
        $min = max($line - $offset, 0);
497
        $pre = null;
498
        $post = null;
499
        if ($min !== $line) {
500
            $pre = array_slice($source, $min, $line - $min);
501
        }
502
        $max = min($line + $offset, $total);
503
        if ($max !== $line) {
504
            $post = array_slice($source, $line + 1, $max - $line);
505
        }
506
        $frame->setContext(new Context($pre, $post));
507
    }
508
509
    private function getTrace($exc)
510
    {
511
        if ($exc instanceof ErrorWrapper) {
512
            return $exc->getBacktrace();
513
        } else {
514
            $trace = $exc->getTrace();
515
            
516
            // Add the Exception's file and line as the last frame of the trace
517
            array_unshift($trace, array('file' => $exc->getFile(), 'line' => $exc->getLine()));
518
            
519
            return $trace;
520
        }
521
    }
522
523
    protected function getMessage($toLog, $context)
524
    {
525
        return new Message(
526
            (string)$toLog,
527
            $context,
528
            $this->sendMessageTrace ?
529
            debug_backtrace($this->localVarsDump ? 0 : DEBUG_BACKTRACE_IGNORE_ARGS) :
530
            null
531
        );
532
    }
533
534
    protected function getLevel($level, $toLog)
535
    {
536
        if (is_null($level)) {
537
            if ($toLog instanceof ErrorWrapper) {
538
                $level = isset($this->errorLevels[$toLog->errorLevel]) ? $this->errorLevels[$toLog->errorLevel] : null;
539
            } elseif ($toLog instanceof \Exception) {
540
                $level = $this->exceptionLevel;
541
            } else {
542
                $level = $this->messageLevel;
543
            }
544
        }
545
        $level = strtolower($level);
546
        $level = isset($this->psrLevels[$level]) ? $this->psrLevels[$level] : null;
547
        return $this->levelFactory->fromName($level);
548
    }
549
550
    protected function getTimestamp()
551
    {
552
        return time();
553
    }
554
555
    protected function getCodeVersion()
556
    {
557
        return $this->codeVersion;
558
    }
559
560
    protected function getPlatform()
561
    {
562
        return $this->platform;
563
    }
564
565
    protected function getLanguage()
566
    {
567
        return "php";
568
        // TODO: once the backend understands a more informative language value
569
        // return "PHP " . phpversion();
570
    }
571
572
    protected function getFramework()
573
    {
574
        return $this->framework;
575
    }
576
577
    protected function getContext()
578
    {
579
        return $this->context;
580
    }
581
582
    /*
583
     * @SuppressWarnings(PHPMD.Superglobals)
584
     */
585
    protected function getRequest()
586
    {
587
        $request = new Request();
588
589
        $request->setUrl($this->getUrl())
590
            ->setHeaders($this->getHeaders())
591
            ->setParams($this->getRequestParams())
592
            ->setBody($this->getRequestBody())
593
            ->setUserIp($this->getUserIp());
594
      
595
        if (isset($_SERVER)) {
596
            $request->setMethod(isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : null)
597
                ->setQueryString(isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : null);
598
        }
599
      
600
        if (isset($_GET)) {
601
            $request->setGet($_GET);
602
        }
603
        if (isset($_POST)) {
604
            $request->setPost($_POST);
605
        }
606
        
607
        if ($request->getMethod() === 'PUT') {
608
            $postData = array();
609
            parse_str($request->getBody(), $postData);
610
            $request->setPost($postData);
611
        }
612
        
613
        $extras = $this->getRequestExtras();
614
        if (!$extras) {
615
            $extras = array();
616
        }
617
618
        $request->setExtras($extras);
619
        
620
        if (isset($_SESSION) && is_array($_SESSION) && count($_SESSION) > 0) {
621
            $request->setSession($_SESSION);
622
        }
623
        return $request;
624
    }
625
    
626
    public function parseForwardedString($forwarded)
627
    {
628
        $result = array();
629
        
630
        // Remove Forwarded   = 1#forwarded-element header prefix
631
        $parts = trim(str_replace('Forwarded:', '', $forwarded));
632
        
633
        /**
634
         * Break up the forwarded-element =
635
         *  [ forwarded-pair ] *( ";" [ forwarded-pair ] )
636
         */
637
        $parts = explode(';', $parts);
638
        
639
        /**
640
         * Parse forwarded pairs
641
         */
642
        foreach ($parts as $forwardedPair) {
643
            $forwardedPair = trim($forwardedPair);
644
            
645
            
646
            if (stripos($forwardedPair, 'host=') !== false) {
647
                // Parse 'host' forwarded pair
648
                $result['host'] = substr($forwardedPair, strlen('host='));
649
            } elseif (stripos($forwardedPair, 'proto=') !== false) {
650
                // Parse 'proto' forwarded pair
651
                $result['proto'] = substr($forwardedPair, strlen('proto='));
652
            } else {
653
                // Parse 'for' and 'by' forwarded pairs which are comma separated
654
                $fpParts = explode(',', $forwardedPair);
655
                foreach ($fpParts as $fpPart) {
656
                    $fpPart = trim($fpPart);
657
                    
658
                    if (stripos($fpPart, 'for=') !== false) {
659
                        // Parse 'for' forwarded pair
660
                        $result['for'] = isset($result['for']) ? $result['for'] : array();
661
                        $result['for'][] = substr($fpPart, strlen('for='));
662
                    } elseif (stripos($fpPart, 'by=') !== false) {
663
                        // Parse 'by' forwarded pair
664
                        $result['by'] = isset($result['by']) ? $result['by'] : array();
665
                        $result['by'][] = substr($fpPart, strlen('by='));
666
                    }
667
                }
668
            }
669
        }
670
        
671
        return $result;
672
    }
673
    
674
    /*
675
     * @SuppressWarnings(PHPMD.Superglobals)
676
     */
677
    public function getUrlProto()
678
    {
679
        $proto = '';
680
        
681
        if (!empty($_SERVER['HTTP_FORWARDED'])) {
682
            extract($this->parseForwardedString($_SERVER['HTTP_FORWARDED']));
683
        }
684
        
685
        if (empty($proto)) {
0 ignored issues
show
introduced by
The condition empty($proto) is always true.
Loading history...
686
            if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
687
                $proto = explode(',', strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']));
688
                $proto = $proto[0];
689
            } elseif (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
690
                $proto = 'https';
691
            } else {
692
                $proto = 'http';
693
            }
694
        }
695
        
696
        return $proto;
697
    }
698
    
699
    /*
700
     * @SuppressWarnings(PHPMD.Superglobals)
701
     */
702
    public function getUrlHost()
703
    {
704
        $host = '';
705
        
706
        if (!empty($_SERVER['HTTP_FORWARDED'])) {
707
            extract($this->parseForwardedString($_SERVER['HTTP_FORWARDED']));
708
        }
709
        
710
        if (empty($host)) {
0 ignored issues
show
introduced by
The condition empty($host) is always true.
Loading history...
711
            if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) {
712
                $host = $_SERVER['HTTP_X_FORWARDED_HOST'];
713
            } elseif (!empty($_SERVER['HTTP_HOST'])) {
714
                $parts = explode(':', $_SERVER['HTTP_HOST']);
715
                $host = $parts[0];
716
            } elseif (!empty($_SERVER['SERVER_NAME'])) {
717
                $host = $_SERVER['SERVER_NAME'];
718
            } else {
719
                $host = 'unknown';
720
            }
721
        }
722
        
723
        return $host;
724
    }
725
    
726
    /*
727
     * @SuppressWarnings(PHPMD.Superglobals)
728
     */
729
    public function getUrlPort($proto)
730
    {
731
        $port = '';
732
        
733
        if (!empty($_SERVER['HTTP_X_FORWARDED_PORT'])) {
734
            $port = $_SERVER['HTTP_X_FORWARDED_PORT'];
735
        } elseif (!empty($_SERVER['SERVER_PORT'])) {
736
            $port = $_SERVER['SERVER_PORT'];
737
        } elseif ($proto === 'https') {
738
            $port = 443;
739
        } else {
740
            $port = 80;
741
        }
742
        
743
        return $port;
744
    }
745
746
    /*
747
     * @SuppressWarnings(PHPMD.Superglobals)
748
     */
749
    public function getUrl()
750
    {
751
        $proto = $this->getUrlProto();
752
        $host = $this->getUrlHost();
753
        $port = $this->getUrlPort($proto);
754
        
755
756
        $url = $proto . '://' . $host;
757
        if (($proto == 'https' && $port != 443) || ($proto == 'http' && $port != 80)) {
758
            $url .= ':' . $port;
759
        }
760
761
        if (isset($_SERVER)) {
762
            $path = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '/';
763
            $url .= $path;
764
        }
765
766
        if ($host == 'unknown') {
767
            $url = null;
768
        }
769
770
        return $url;
771
    }
772
773
    /*
774
     * @SuppressWarnings(PHPMD.Superglobals)
775
     */
776
    public function getHeaders()
777
    {
778
        $headers = array();
779
        if (isset($_SERVER)) {
780
            foreach ($_SERVER as $key => $val) {
781
                if (substr($key, 0, 5) == 'HTTP_') {
782
                    // convert HTTP_CONTENT_TYPE to Content-Type, HTTP_HOST to Host, etc.
783
                    $name = strtolower(substr($key, 5));
784
                    $name = str_replace(' ', '-', ucwords(str_replace('_', ' ', $name)));
785
                    $headers[$name] = $val;
786
                }
787
            }
788
        }
789
        if (count($headers) > 0) {
790
            return $headers;
791
        } else {
792
            return null;
793
        }
794
    }
795
796
    
797
    protected function getRequestParams()
798
    {
799
        return $this->requestParams;
800
    }
801
802
    protected function getRequestBody()
803
    {
804
        return $this->requestBody;
805
    }
806
807
    /*
808
     * @SuppressWarnings(PHPMD.Superglobals)
809
     */
810
    protected function getUserIp()
811
    {
812
        if (!isset($_SERVER) || $this->captureIP === false) {
813
            return null;
814
        }
815
        
816
        $ipAddress = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null;
817
        
818
        $forwardFor = isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : null;
819
        if ($forwardFor) {
820
            // return everything until the first comma
821
            $parts = explode(',', $forwardFor);
822
            $ipAddress = $parts[0];
823
        }
824
        $realIp = isset($_SERVER['HTTP_X_REAL_IP']) ? $_SERVER['HTTP_X_REAL_IP'] : null;
825
        if ($realIp) {
826
            $ipAddress = $realIp;
827
        }
828
        
829
        if ($this->captureIP === DataBuilder::ANONYMIZE_IP) {
830
            if (filter_var($ipAddress, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
831
                $parts = explode('.', $ipAddress);
832
                $ipAddress = $parts[0] . '.' . $parts[1] . '.' . $parts[2] . '.0';
833
            } elseif (filter_var($ipAddress, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
834
                $parts = explode(':', $ipAddress);
835
                $ipAddress =
836
                    $parts[0] . ':' .
837
                    $parts[1] . ':' .
838
                    $parts[2] . ':' .
839
                    '0000:0000:0000:0000:0000';
840
            }
841
        }
842
        
843
        return $ipAddress;
844
    }
845
846
    protected function getRequestExtras()
847
    {
848
        return $this->requestExtras;
849
    }
850
851
    /**
852
     * @return Person
853
     */
854
    protected function getPerson()
855
    {
856
        $personData = $this->person;
857
        if (!isset($personData) && is_callable($this->personFunc)) {
858
            try {
859
                $personData = call_user_func($this->personFunc);
860
            } catch (\Exception $exception) {
861
                Rollbar::scope(array('person_fn' => null))->
862
                    log(Level::ERROR, $exception);
863
            }
864
        }
865
866
        if (!isset($personData['id'])) {
867
            return null;
868
        }
869
870
        $identifier = $personData['id'];
871
872
        $email = null;
873
        if ($this->captureEmail && isset($personData['email'])) {
874
            $email = $personData['email'];
875
        }
876
877
        $username = null;
878
        if ($this->captureUsername && isset($personData['username'])) {
879
            $username = $personData['username'];
880
        }
881
882
        unset($personData['id'], $personData['email'], $personData['username']);
883
        return new Person($identifier, $username, $email, $personData);
884
    }
885
886
    /*
887
     * @SuppressWarnings(PHPMD.Superglobals)
888
     */
889
    protected function getServer()
890
    {
891
        $server = new Server();
892
        $server->setHost($this->getHost())
893
            ->setRoot($this->getServerRoot())
894
            ->setBranch($this->getServerBranch())
895
            ->setCodeVersion($this->getServerCodeVersion());
896
        $extras = $this->getServerExtras();
897
        if (!$extras) {
898
            $extras = array();
899
        }
900
901
        $server->setExtras($extras);
902
        if (isset($_SERVER) && array_key_exists('argv', $_SERVER)) {
903
            $server->setArgv($_SERVER['argv']);
904
        }
905
        return $server;
906
    }
907
908
    protected function getHost()
909
    {
910
        if (isset($this->host)) {
911
            return $this->host;
912
        }
913
        return gethostname();
914
    }
915
916
    protected function getServerRoot()
917
    {
918
        return $this->serverRoot;
919
    }
920
921
    protected function getServerBranch()
922
    {
923
        return $this->serverBranch;
924
    }
925
926
    protected function getServerCodeVersion()
927
    {
928
        return $this->serverCodeVersion;
929
    }
930
931
    protected function getServerExtras()
932
    {
933
        return $this->serverExtras;
934
    }
935
    
936
    public function getCustom()
937
    {
938
        return $this->custom;
939
    }
940
    
941
    public function getCustomDataMethod()
942
    {
943
        return $this->customDataMethod;
944
    }
945
946
    protected function getCustomForPayload($toLog, $context)
947
    {
948
        $custom = $this->getCustom();
949
950
        // Make this an array if possible:
951
        if ($custom instanceof \Serializable) {
952
            $custom = $custom->serialize();
953
        } elseif (is_null($custom)) {
954
            $custom = array();
955
        } elseif (!is_array($custom)) {
956
            $custom = get_object_vars($custom);
957
        }
958
        
959
        if ($customDataMethod = $this->getCustomDataMethod()) {
960
            $customDataMethodContext = isset($context['custom_data_method_context']) ?
961
                $context['custom_data_method_context'] :
962
                null;
963
                
964
            $customDataMethodResult = $customDataMethod($toLog, $customDataMethodContext);
965
            
966
            $custom = array_merge($custom, $customDataMethodResult);
0 ignored issues
show
Bug introduced by
It seems like $custom can also be of type string; however, parameter $array1 of array_merge() 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

966
            $custom = array_merge(/** @scrutinizer ignore-type */ $custom, $customDataMethodResult);
Loading history...
967
        }
968
        
969
        unset($context['custom_data_method_context']);
970
971
        return array_replace_recursive(array(), $context, $custom);
0 ignored issues
show
Bug introduced by
It seems like $custom can also be of type string; however, parameter $array2 of array_replace_recursive() does only seem to accept null|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

971
        return array_replace_recursive(array(), $context, /** @scrutinizer ignore-type */ $custom);
Loading history...
972
    }
973
    
974
    public function addCustom($key, $data)
975
    {
976
        if ($this->custom === null) {
977
            $this->custom = array();
978
        }
979
        
980
        if (!is_array($this->custom)) {
981
            throw new \Exception(
982
                "Custom data configured in Rollbar::init() is not an array."
983
            );
984
        }
985
        
986
        $this->custom[$key] = $data;
987
    }
988
    
989
    public function removeCustom($key)
990
    {
991
        unset($this->custom[$key]);
992
    }
993
994
    protected function getFingerprint($context)
995
    {
996
        return isset($context['fingerprint']) ? $context['fingerprint'] : $this->fingerprint;
997
    }
998
999
    protected function getTitle()
1000
    {
1001
        return $this->title;
1002
    }
1003
1004
    protected function getUuid()
1005
    {
1006
        return $this->utilities->uuid4();
1007
    }
1008
1009
    protected function getNotifier()
1010
    {
1011
        return $this->notifier;
1012
    }
1013
1014
    protected function getBaseException()
1015
    {
1016
        return $this->baseException;
1017
    }
1018
1019
    /**
1020
     * Parses an array of code lines from source file with given filename.
1021
     *
1022
     * Attempts to automatically detect the line break character used in the file.
1023
     *
1024
     * @param string $filename
1025
     * @return string[] An array of lines of code from the given source file.
1026
     */
1027
    private function getSourceLines($filename)
1028
    {
1029
        $rawSource = file_get_contents($filename);
1030
1031
        $source = explode(PHP_EOL, $rawSource);
1032
1033
        if (count($source) === 1) {
1034
            if (substr_count($rawSource, "\n") > substr_count($rawSource, "\r")) {
1035
                $source = explode("\n", $rawSource);
1036
            } else {
1037
                $source = explode("\r", $rawSource);
1038
            }
1039
        }
1040
1041
        $source = str_replace(array("\n", "\t", "\r"), '', $source);
1042
1043
        return $source;
1044
    }
1045
    
1046
    /**
1047
     * Wrap a PHP error in an ErrorWrapper class and add backtrace information
1048
     *
1049
     * @param string $errno
1050
     * @param string $errstr
1051
     * @param string $errfile
1052
     * @param string $errline
1053
     *
1054
     * @return ErrorWrapper
1055
     */
1056
    public function generateErrorWrapper($errno, $errstr, $errfile, $errline)
1057
    {
1058
        return new ErrorWrapper(
1059
            $errno,
1060
            $errstr,
1061
            $errfile,
1062
            $errline,
1063
            $this->buildErrorTrace($errfile, $errline),
1064
            $this->utilities
1065
        );
1066
    }
1067
    
1068
    /**
1069
     * Fetches the stack trace for fatal and regular errors.
1070
     *
1071
     * @var string $errfile
1072
     * @var string $errline
1073
     *
1074
     * @return Rollbar\ErrorWrapper
0 ignored issues
show
Bug introduced by
The type Rollbar\Rollbar\ErrorWrapper was not found. Did you mean Rollbar\ErrorWrapper? If so, make sure to prefix the type with \.
Loading history...
1075
     */
1076
    protected function buildErrorTrace($errfile, $errline)
1077
    {
1078
        if ($this->captureErrorStacktraces) {
1079
            $backTrace = $this->fetchErrorTrace();
1080
            
1081
            $backTrace = $this->stripShutdownFrames($backTrace);
1082
            
1083
            // Add the final frame
1084
            array_unshift(
1085
                $backTrace,
1086
                array('file' => $errfile, 'line' => $errline)
1087
            );
1088
        } else {
1089
            $backTrace = array();
1090
        }
1091
        
1092
        return $backTrace;
1093
    }
1094
    
1095
    private function fetchErrorTrace()
1096
    {
1097
        if (function_exists('xdebug_get_function_stack')) {
1098
            return array_reverse(\xdebug_get_function_stack());
1099
        } else {
1100
            return debug_backtrace($this->localVarsDump ? 0 : DEBUG_BACKTRACE_IGNORE_ARGS);
1101
        }
1102
    }
1103
    
1104
    private function stripShutdownFrames($backTrace)
1105
    {
1106
        foreach ($backTrace as $index => $frame) {
1107
            extract($frame);
1108
            
1109
            $fatalHandlerMethod = (isset($method)
1110
                                    && $method === 'Rollbar\\Handlers\\FatalHandler::handle');
1111
                                    
1112
            $fatalHandlerClassAndFunction = (isset($class)
1113
                                                && $class === 'Rollbar\\Handlers\\FatalHandler'
1114
                                                && isset($function)
1115
                                                && $function === 'handle');
1116
            
1117
            $errorHandlerMethod = (isset($method)
1118
                                    && $method === 'Rollbar\\Handlers\\ErrorHandler::handle');
1119
                                    
1120
            $errorHandlerClassAndFunction = (isset($class)
1121
                                                && $class === 'Rollbar\\Handlers\\ErrorHandler'
1122
                                                && isset($function)
1123
                                                && $function === 'handle');
1124
            
1125
            if ($fatalHandlerMethod ||
1126
                 $fatalHandlerClassAndFunction ||
1127
                 $errorHandlerMethod ||
1128
                 $errorHandlerClassAndFunction ) {
1129
                return array_slice($backTrace, $index+1);
1130
            }
1131
        }
1132
        
1133
        return $backTrace;
1134
    }
1135
}
1136