Completed
Push — master ( 57a6c0...17a4a8 )
by Aivis
03:00 queued 01:24
created

FieldProvider::getPostDataArray()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 37

Duplication

Lines 11
Ratio 29.73 %

Importance

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