Completed
Pull Request — master (#40)
by
unknown
01:24
created

FieldProvider::getRequestMethod()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.9666
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php namespace Understand\UnderstandLaravel5;
2
3
use Understand\UnderstandLaravel5\UniqueProcessIdentifier;
4
use \Illuminate\Session\Store AS SessionStore;
5
use \Illuminate\Routing\Router;
6
use Illuminate\Http\Request;
7
use Illuminate\Foundation\Application;
8
9
class FieldProvider
10
{
11
12
    /**
13
     * The registered field providers.
14
     *
15
     * @var array
16
     */
17
    protected $providers = [];
18
19
    /**
20
     * Default field
21
     *
22
     * @var array
23
     */
24
    protected $defaultProviders = [
25
        'getSessionId',
26
        'getRouteName',
27
        'getUrl',
28
        'getRequestMethod',
29
        'getServerIp',
30
        'getClientIp',
31
        'getClientUserAgent',
32
        'getEnvironment',
33
        'getFromSession',
34
        'getProcessIdentifier',
35
        'getUserId',
36
        'getGroupId',
37
        'getLaravelVersion',
38
        'getSqlQueries',
39
        'getArtisanCommandName',
40
        'getRunningInConsole',
41
        'getLoggerVersion',
42
        'getPostDataArray',
43
        'getQueryStringArray',
44
    ];
45
46
    /**
47
     * Session store
48
     *
49
     * @var \Illuminate\Session\Store
50
     */
51
    protected $session;
52
53
    /**
54
     * Router
55
     *
56
     * @var Router
57
     */
58
    protected $router;
59
60
    /**
61
     * Server variable
62
     *
63
     * @var Request
64
     */
65
    protected $request;
66
67
    /**
68
     * Token provider
69
     *
70
     * @var UniqueProcessIdentifier
71
     */
72
    protected $tokenProvider;
73
74
    /**
75
     * Current environment
76
     *
77
     * @var string
78
     */
79
    protected $environment;
80
81
    /**
82
     * @var DataCollector
83
     */
84
    protected $dataCollector;
85
86
    /**
87
     * @var Application
88
     */
89
    protected $app;
90
91
    /**
92
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
93
     */
94
    public function __construct()
95
    {
96
        foreach ($this->defaultProviders as $defaultProviderName)
97
        {
98
            $this->extend($defaultProviderName, [$this, $defaultProviderName]);
99
        }
100
    }
101
102
    /**
103
     * @param Application $app
104
     */
105
    public function setApp($app)
106
    {
107
        $this->app = $app;
108
    }
109
110
    /**
111
     * Set session store
112
     *
113
     * @param type $service
114
     */
115
    public function setSessionStore(SessionStore $service)
116
    {
117
        $this->session = $service;
118
    }
119
120
    /**
121
     * Set router
122
     *
123
     * @param Router $router
124
     */
125
    public function setRouter($router)
126
    {
127
        $this->router = $router;
128
    }
129
130
    /**
131
     * Set request
132
     *
133
     * @param Request $request
134
     */
135
    public function setRequest(Request $request)
0 ignored issues
show
Bug introduced by
You have injected the Request via parameter $request. This is generally not recommended as there might be multiple instances during a request cycle (f.e. when using sub-requests). Instead, it is recommended to inject the RequestStack and retrieve the current request each time you need it via getCurrentRequest().
Loading history...
136
    {
137
        $this->request = $request;
138
    }
139
140
    /**
141
     * Set current environment
142
     *
143
     * @param string $environment
144
     */
145
    public function setEnvironment($environment)
146
    {
147
        $this->environment = $environment;
148
    }
149
150
    /**
151
     * @param DataCollector $dataCollector
152
     */
153
    public function setDataCollector(DataCollector $dataCollector)
154
    {
155
        $this->dataCollector = $dataCollector;
156
    }
157
158
    /**
159
     * Register a custom HTML macro.
160
     *
161
     * @param string $name
162
     * @param  mixed  $macro
0 ignored issues
show
Bug introduced by
There is no parameter named $macro. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
163
     * @return void
164
     */
165
    public function extend($name, $provider)
166
    {
167
        $this->providers[$name] = $provider;
168
    }
169
170
    /**
171
     * Set token provider
172
     *
173
     * @param UniqueProcessIdentifier $tokenProvider
174
     */
175
    public function setTokenProvider(TokenProvider $tokenProvider)
176
    {
177
        $this->tokenProvider = $tokenProvider;
0 ignored issues
show
Documentation Bug introduced by
It seems like $tokenProvider of type object<Understand\Unders...Laravel5\TokenProvider> is incompatible with the declared type object<Understand\Unders...niqueProcessIdentifier> of property $tokenProvider.

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

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

Loading history...
178
    }
179
180
    /**
181
     * Return resolved field-value array
182
     *
183
     * @param array $callbacks
184
     * @param array $log
185
     * @return array
186
     */
187
    public function resolveValues(array $callbacks, array $log)
188
    {
189
        $data = [];
190
191
        foreach ($callbacks as $fieldName => $caller)
192
        {
193
            if (!is_array($caller))
194
            {
195
                $caller = [$caller];
196
            }
197
198
            $callback = array_get($caller, 0);
199
            $args = [$log];
200
201
            $value = call_user_func_array($callback, $args);
202
203
            $data[$fieldName] = $value;
204
        }
205
206
        return $data;
207
    }
208
209
    /**
210
     * Handle class calls
211
     *
212
     * @param string $name
213
     * @param  mixed $params
214
     * @return mixed
215
     *
216
     * @throws \BadMethodCallException
217
     */
218
    public function __call($name, $params)
219
    {
220
        if (isset($this->providers[$name]))
221
        {
222
            return call_user_func_array($this->providers[$name], $params);
223
        }
224
225
        throw new \BadMethodCallException("Method {$name} does not exist.");
226
    }
227
228
    /**
229
     * Return hashed version of session id
230
     *
231
     * @return string
232
     */
233
    protected function getSessionId()
234
    {
235
        if ( ! $this->session)
236
        {
237
            return null;
238
        }
239
240
        $sessionId = $this->session->getId();
241
242
        // by default we provide only hashed version of session id
243
        $hashed = sha1($sessionId);
244
245
        return $hashed;
246
    }
247
248
    /**
249
     * Detect if the application is Laravel or Lumen
250
     *
251
     * @return bool
252
     */
253
    protected function isLaravel()
254
    {
255
        return $this->app instanceof Application;
256
    }
257
258
    /**
259
     * Get Laravel/Lumen version
260
     *
261
     * @return string
262
     */
263
    protected function getLaravelVersion()
264
    {
265
        if ($this->isLaravel())
266
        {
267
            // Laravel
268
            return Application::VERSION;
269
        }
270
        else
271
        {
272
            $re = '/Lumen \((.*)\) \(.*\)/m';
273
274
            $version = $this->app->version();
275
276
            preg_match($re, $version, $matches);
277
278
            return $matches[1];
279
        }
280
    }
281
282
    /**
283
     * @return array
284
     */
285
    protected function getSqlQueries()
286
    {
287
        if ( ! $this->dataCollector)
288
        {
289
            return [];
290
        }
291
292
        $queries = $this->dataCollector->getByKey('sql_queries');
293
294
        if ( ! $queries)
295
        {
296
            return null;
297
        }
298
299
        $bindingsEnabled = $this->app['config']->get('understand-laravel.sql_bindings');
300
301
        foreach($queries as $key => $queryArray)
302
        {
303
            if ($bindingsEnabled)
304
            {
305
                $queries[$key]['query'] = $this->mergeBindings($queryArray);
306
            }
307
308
            unset($queries[$key]['bindings']);
309
        }
310
311
        return $queries;
312
    }
313
314
    /**
315
     * @param $queryArray
316
     * @return mixed
317
     */
318
    protected function mergeBindings($queryArray)
319
    {
320
        $sqlQuery = $queryArray['query'];
321
        $placeholder = '?';
322
323
        foreach($queryArray['bindings'] as $key => $value)
324
        {
325
            try
326
            {
327
                if ($value instanceof \DateTimeInterface)
328
                {
329
                    $binding = $value->format('Y-m-d H:i:s');
330
                }
331
                elseif (is_bool($value))
332
                {
333
                    $binding = (int) $value;
334
                }
335
                else
336
                {
337
                    $binding = (string)$value;
338
                }
339
            }
340
            catch (\Exception $e)
341
            {
342
                $binding = '[handler error]';
343
            }
344
345
            $position = strpos($sqlQuery, $placeholder);
346
347
            if ($position !== false)
348
            {
349
                $sqlQuery = substr_replace($sqlQuery, $binding, $position, strlen($placeholder));
350
            }
351
        }
352
353
        return $sqlQuery;
354
}
355
356
    /**
357
     * Return current route name
358
     *
359
     * @return string
360
     */
361
    protected function getRouteName()
362
    {
363
        if ( ! $this->router)
364
        {
365
            return null;
366
        }
367
368
        return $this->router->getCurrentRoute()->getName();
369
    }
370
371
    /**
372
     * Return current url
373
     *
374
     * @return string
375
     */
376
    protected function getUrl()
377
    {
378
        if ( ! $this->request)
379
        {
380
            return null;
381
        }
382
383
        $url = $this->request->path();
384
385
        if ( ! starts_with($url, '/'))
386
        {
387
            $url = '/' . $url;
388
        }
389
390
        return $url;
391
    }
392
393
    /**
394
     * @return array|null
395
     */
396
    protected function getQueryStringArray()
397
    {
398
        $enabled = $this->app['config']->get('understand-laravel.query_string_enabled');
399
400
        if ( ! $enabled)
401
        {
402
            return null;
403
        }
404
405
        if ( ! $this->request->query instanceof \IteratorAggregate)
406
        {
407
            return null;
408
        }
409
410
        $queryString = [];
411
412
        foreach($this->request->query as $key => $value)
413
        {
414
            try
415
            {
416
                $queryString[$key] = $this->parseRequestFieldValue($key, $value);
417
            }
418
            catch (\Exception $e)
419
            {
420
                $queryString[$key] = '[handler error]';
421
            }
422
        }
423
424
        return $queryString;
425
    }
426
427
    /**
428
     * @return array|null
429
     */
430
    protected function getPostDataArray()
431
    {
432
        $enabled = $this->app['config']->get('understand-laravel.post_data_enabled');
433
434
        if ( ! $enabled)
435
        {
436
            return null;
437
        }
438
439
        // Laravel merge and update the symphony `request` property that should hold only POST data
440
        // by checking if the request method is not GET or HEAD we can decide whether to use it or not
441
        if (in_array($this->request->getRealMethod(), ['GET', 'HEAD']))
442
        {
443
            return null;
444
        }
445
446
        $source = null;
0 ignored issues
show
Unused Code introduced by
$source is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
447
448
        if (method_exists($this->request, 'json') && method_exists($this->request, 'isJson') && $this->request->isJson())
449
        {
450
            $source = $this->request->json();
451
        }
452
        else if ($this->request->request instanceof \IteratorAggregate)
453
        {
454
            $source = $this->request->request;
455
        }
456
        else
457
        {
458
            return;
459
        }
460
461
        if ( ! $source)
462
        {
463
            return;
464
        }
465
466
        $postData = [];
467
468
        foreach($source as $key => $value)
469
        {
470
            try
471
            {
472
                $postData[$key] = $this->parseRequestFieldValue($key, $value);
473
            }
474
            catch (\Exception $e)
475
            {
476
                $postData[$key] = '[handler error]';
477
            }
478
        }
479
480
        return $postData;
481
    }
482
483
    /**
484
     * @param $key
485
     * @param $value
486
     * @return mixed|string
487
     */
488
    protected function parseRequestFieldValue($key, $value)
489
    {
490
        $hiddenFields = $this->app['config']->get('understand-laravel.hidden_fields', []);
491
492
        if (in_array($key, $hiddenFields))
493
        {
494
            return '[value hidden]';
495
        }
496
497
        if (is_scalar($value))
498
        {
499
            return $value;
500
        }
501
502
        if (is_array($value))
503
        {
504
            return print_r($value, true);
505
        }
506
507
        if (is_object($value))
508
        {
509
            return get_class($value);
510
        }
511
512
        return (string)$value;
513
    }
514
515
    /**
516
     * Return request method
517
     *
518
     * @return string
519
     */
520
    protected function getRequestMethod()
521
    {
522
        if ( ! $this->request)
523
        {
524
            return null;
525
        }
526
527
        return $this->request->method();
528
    }
529
530
    /**
531
     * Return server ip address
532
     *
533
     * @return string
534
     */
535
    protected function getServerIp()
536
    {
537
        if ( ! $this->request)
538
        {
539
            return null;
540
        }
541
542
        return $this->request->server->get('SERVER_ADDR');
543
    }
544
545
    /**
546
     * Return client ip
547
     *
548
     * @return string
549
     */
550
    protected function getClientIp()
551
    {
552
        if ( ! $this->request)
553
        {
554
            return null;
555
        }
556
557
        return $this->request->getClientIp();
558
    }
559
560
    /**
561
     * Return client user agent string
562
     *
563
     * @return string
564
     */
565
    protected function getClientUserAgent()
566
    {
567
        if ( ! $this->request)
568
        {
569
            return null;
570
        }
571
572
        return $this->request->server->get('HTTP_USER_AGENT');
573
    }
574
575
    /**
576
     * Return current enviroment
577
     *
578
     * @return string
579
     */
580
    protected function getEnvironment()
581
    {
582
        return $this->environment;
583
    }
584
585
    /**
586
     * Retrive parameter from current session
587
     *
588
     * @param string $key
589
     * @return string
590
     */
591
    protected function getFromSession($key)
592
    {
593
        if ( ! $this->session)
594
        {
595
            return null;
596
        }
597
598
        return $this->session->get($key);
599
    }
600
601
    /**
602
     * Return group id
603
     *
604
     * @param array $log
605
     * @return string
606
     */
607
    protected function getGroupId(array $log)
608
    {
609
        $parts = [];
610
611
        foreach(['class', 'file', 'line', 'code'] as $field)
612
        {
613
            // only include `code` if it's not null value
614
            // the `code` attribute of the exception object is useful to differentiate SQL and other exceptions
615
            //
616
            // https://www.php.net/manual/en/exception.getcode.php
617
            // https://www.php.net/manual/en/pdo.errorinfo.php
618
            // https://docs.oracle.com/cd/E15817_01/appdev.111/b31228/appd.htm
619
            if ($field == 'code' && empty($log[$field]))
620
            {
621
                continue;
622
            }
623
624
            $parts[] = isset($log[$field]) ? (string)$log[$field] : null;
625
        }
626
627
        return sha1(implode('#', $parts));
628
    }
629
630
    /**
631
     * Return current active user id
632
     *
633
     * @return int
634
     */
635
    protected function getUserId()
636
    {
637
        try
638
        {
639
            if (class_exists('\Auth') && ($userId = \Auth::id()))
640
            {
641
                return $userId;
642
            }
643
        }
644
        catch (\Throwable $e)
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
Bug introduced by
The class Throwable does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
645
        {}
646
        catch (\Exception $e)
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
647
        {}
648
649
        try
650
        {
651
            if (class_exists('\Sentinel') && ($user = \Sentinel::getUser()))
652
            {
653
                return $user->id;
654
            }
655
        }
656
        catch (\Throwable $e)
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
Bug introduced by
The class Throwable does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
657
        {}
658
        catch (\Exception $e)
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
659
        {}
660
661
        try
662
        {
663
            if (class_exists('\Sentry') && ($user = \Sentry::getUser()))
664
            {
665
                return $user->id;
666
            }
667
        }
668
        catch (\Throwable $e)
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
Bug introduced by
The class Throwable does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
669
        {}
670
        catch (\Exception $e)
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
671
        {}
672
    }
673
674
    /**
675
     * @return string
676
     */
677
    protected function getArtisanCommandName()
678
    {
679
        if ($this->app->runningInConsole() && isset($_SERVER['argv']))
680
        {
681
            return implode(' ', $_SERVER['argv']);
682
        }
683
    }
684
685
    /**
686
     * @return bool
687
     */
688
    protected function getRunningInConsole()
689
    {
690
        return $this->app->runningInConsole();
691
    }
692
693
    /**
694
     * @return float
695
     */
696
    protected function getLoggerVersion()
697
    {
698
        return Logger::VERSION;
699
    }
700
701
    /**
702
     * Return process identifier token
703
     *
704
     * @return string
705
     */
706
    protected function getProcessIdentifier()
707
    {
708
        return $this->tokenProvider->getToken();
709
    }
710
711
}
712