Completed
Push — master ( 0decdc...293236 )
by Aivis
22s queued 11s
created

FieldProvider::parseRequestFieldValue()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 26
rs 9.1928
c 0
b 0
f 0
cc 5
nc 5
nop 2
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(Application $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 $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
     * @return string
250
     */
251
    protected function getLaravelVersion()
252
    {
253
        return Application::VERSION;
254
    }
255
256
    /**
257
     * @return array
258
     */
259
    protected function getSqlQueries()
260
    {
261
        if ( ! $this->dataCollector)
262
        {
263
            return [];
264
        }
265
266
        $queries = $this->dataCollector->getByKey('sql_queries');
267
268
        if ( ! $queries)
269
        {
270
            return null;
271
        }
272
273
        $bindingsEnabled = $this->app['config']->get('understand-laravel.sql_bindings');
274
275
        foreach($queries as $key => $queryArray)
276
        {
277
            if ($bindingsEnabled)
278
            {
279
                $queries[$key]['query'] = $this->mergeBindings($queryArray);
280
            }
281
282
            unset($queries[$key]['bindings']);
283
        }
284
285
        return $queries;
286
    }
287
288
    /**
289
     * @param $queryArray
290
     * @return mixed
291
     */
292
    protected function mergeBindings($queryArray)
293
    {
294
        $sqlQuery = $queryArray['query'];
295
        $placeholder = '?';
296
297
        foreach($queryArray['bindings'] as $key => $value)
298
        {
299
            try
300
            {
301
                if ($value instanceof \DateTimeInterface)
302
                {
303
                    $binding = $value->format('Y-m-d H:i:s');
304
                }
305
                elseif (is_bool($value))
306
                {
307
                    $binding = (int) $value;
308
                }
309
                else
310
                {
311
                    $binding = (string)$value;
312
                }
313
            }
314
            catch (\Exception $e)
315
            {
316
                $binding = '[handler error]';
317
            }
318
319
            $position = strpos($sqlQuery, $placeholder);
320
321
            if ($position !== false)
322
            {
323
                $sqlQuery = substr_replace($sqlQuery, $binding, $position, strlen($placeholder));
324
            }
325
        }
326
327
        return $sqlQuery;
328
}
329
330
    /**
331
     * Return current route name
332
     *
333
     * @return string
334
     */
335
    protected function getRouteName()
336
    {
337
        if ( ! $this->router)
338
        {
339
            return null;
340
        }
341
342
        return $this->router->getCurrentRoute()->getName();
343
    }
344
345
    /**
346
     * Return current url
347
     *
348
     * @return string
349
     */
350
    protected function getUrl()
351
    {
352
        if ( ! $this->request)
353
        {
354
            return null;
355
        }
356
357
        $url = $this->request->path();
358
359
        if ( ! starts_with($url, '/'))
360
        {
361
            $url = '/' . $url;
362
        }
363
364
        return $url;
365
    }
366
367
    /**
368
     * @return array|null
369
     */
370 View Code Duplication
    protected function getQueryStringArray()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
371
    {
372
        $enabled = $this->app['config']->get('understand-laravel.query_string_enabled');
373
374
        if ( ! $enabled)
375
        {
376
            return null;
377
        }
378
379
        if ( ! $this->request->query instanceof \IteratorAggregate)
380
        {
381
            return null;
382
        }
383
384
        $queryString = [];
385
386
        foreach($this->request->query as $key => $value)
387
        {
388
            try
389
            {
390
                $queryString[$key] = $this->parseRequestFieldValue($key, $value);
391
            }
392
            catch (\Exception $e)
393
            {
394
                $queryString[$key] = '[handler error]';
395
            }
396
        }
397
398
        return $queryString;
399
    }
400
401
    /**
402
     * @return array|null
403
     */
404 View Code Duplication
    protected function getPostDataArray()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
405
    {
406
        $enabled = $this->app['config']->get('understand-laravel.post_data_enabled');
407
408
        if ( ! $enabled)
409
        {
410
            return null;
411
        }
412
413
        if ( ! $this->request->request instanceof \IteratorAggregate)
414
        {
415
            return null;
416
        }
417
418
        $postData = [];
419
420
        foreach($this->request->request as $key => $value)
421
        {
422
            try
423
            {
424
                $postData[$key] = $this->parseRequestFieldValue($key, $value);
425
            }
426
            catch (\Exception $e)
427
            {
428
                $postData[$key] = '[handler error]';
429
            }
430
        }
431
432
        return $postData;
433
    }
434
435
    /**
436
     * @param $key
437
     * @param $value
438
     * @return mixed|string
439
     */
440
    protected function parseRequestFieldValue($key, $value)
441
    {
442
        $hiddenFields = $this->app['config']->get('understand-laravel.hidden_fields', []);
443
444
        if (in_array($key, $hiddenFields))
445
        {
446
            return '[value hidden]';
447
        }
448
449
        if (is_scalar($value))
450
        {
451
            return $value;
452
        }
453
454
        if (is_array($value))
455
        {
456
            return print_r($value, true);
457
        }
458
459
        if (is_object($value))
460
        {
461
            return get_class($value);
462
        }
463
464
        return (string)$value;
465
    }
466
467
    /**
468
     * Return request method
469
     *
470
     * @return string
471
     */
472
    protected function getRequestMethod()
473
    {
474
        if ( ! $this->request)
475
        {
476
            return null;
477
        }
478
479
        return $this->request->method();
480
    }
481
482
    /**
483
     * Return server ip address
484
     *
485
     * @return string
486
     */
487
    protected function getServerIp()
488
    {
489
        if ( ! $this->request)
490
        {
491
            return null;
492
        }
493
494
        return $this->request->server->get('SERVER_ADDR');
495
    }
496
497
    /**
498
     * Return client ip
499
     *
500
     * @return string
501
     */
502
    protected function getClientIp()
503
    {
504
        if ( ! $this->request)
505
        {
506
            return null;
507
        }
508
509
        return $this->request->getClientIp();
510
    }
511
512
    /**
513
     * Return client user agent string
514
     *
515
     * @return string
516
     */
517
    protected function getClientUserAgent()
518
    {
519
        if ( ! $this->request)
520
        {
521
            return null;
522
        }
523
524
        return $this->request->server->get('HTTP_USER_AGENT');
525
    }
526
527
    /**
528
     * Return current enviroment
529
     *
530
     * @return string
531
     */
532
    protected function getEnvironment()
533
    {
534
        return $this->environment;
535
    }
536
537
    /**
538
     * Retrive parameter from current session
539
     *
540
     * @param string $key
541
     * @return string
542
     */
543
    protected function getFromSession($key)
544
    {
545
        if ( ! $this->session)
546
        {
547
            return null;
548
        }
549
550
        return $this->session->get($key);
551
    }
552
553
    /**
554
     * Return group id
555
     *
556
     * @param array $log
557
     * @return string
558
     */
559
    protected function getGroupId(array $log)
560
    {
561
        $parts = [];
562
563
        foreach(['class', 'file', 'line', 'code'] as $field)
564
        {
565
            // only include `code` if it's not null value
566
            // the `code` attribute of the exception object is useful to differentiate SQL and other exceptions
567
            //
568
            // https://www.php.net/manual/en/exception.getcode.php
569
            // https://www.php.net/manual/en/pdo.errorinfo.php
570
            // https://docs.oracle.com/cd/E15817_01/appdev.111/b31228/appd.htm
571
            if ($field == 'code' && empty($log[$field]))
572
            {
573
                continue;
574
            }
575
576
            $parts[] = isset($log[$field]) ? (string)$log[$field] : null;
577
        }
578
579
        return sha1(implode('#', $parts));
580
    }
581
582
    /**
583
     * Return current active user id
584
     *
585
     * @return int
586
     */
587
    protected function getUserId()
588
    {
589
        try
590
        {
591
            if (class_exists('\Auth') && ($userId = \Auth::id()))
592
            {
593
                return $userId;
594
            }
595
        }
596
        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...
597
        {}
598
        catch (\Exception $e)
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
599
        {}
600
601
        try
602
        {
603
            if (class_exists('\Sentinel') && ($user = \Sentinel::getUser()))
604
            {
605
                return $user->id;
606
            }
607
        }
608
        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...
609
        {}
610
        catch (\Exception $e)
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
611
        {}
612
613
        try
614
        {
615
            if (class_exists('\Sentry') && ($user = \Sentry::getUser()))
616
            {
617
                return $user->id;
618
            }
619
        }
620
        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...
621
        {}
622
        catch (\Exception $e)
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
623
        {}
624
    }
625
626
    /**
627
     * @return string
628
     */
629
    protected function getArtisanCommandName()
630
    {
631
        if ($this->app->runningInConsole() && isset($_SERVER['argv']))
632
        {
633
            return implode(' ', $_SERVER['argv']);
634
        }
635
    }
636
637
    /**
638
     * @return bool
639
     */
640
    protected function getRunningInConsole()
641
    {
642
        return $this->app->runningInConsole();
643
    }
644
645
    /**
646
     * @return float
647
     */
648
    protected function getLoggerVersion()
649
    {
650
        return Logger::VERSION;
651
    }
652
653
    /**
654
     * Return process identifier token
655
     *
656
     * @return string
657
     */
658
    protected function getProcessIdentifier()
659
    {
660
        return $this->tokenProvider->getToken();
661
    }
662
663
}
664