Completed
Pull Request — master (#33)
by Aivis
02:47
created

FieldProvider::getProcessIdentifier()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
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
            if ($value instanceof \DateTimeInterface)
300
            {
301
                $binding = $value->format('Y-m-d H:i:s');
302
            }
303
            elseif (is_bool($value))
304
            {
305
                $binding = (int) $value;
306
            }
307
            else
308
            {
309
                $binding = $value;
310
            }
311
312
            $position = strpos($sqlQuery, $placeholder);
313
314
            if ($position !== false)
315
            {
316
                $sqlQuery = substr_replace($sqlQuery, $binding, $position, strlen($placeholder));
317
            }
318
        }
319
320
        return $sqlQuery;
321
}
322
323
    /**
324
     * Return current route name
325
     *
326
     * @return string
327
     */
328
    protected function getRouteName()
329
    {
330
        if ( ! $this->router)
331
        {
332
            return null;
333
        }
334
335
        return $this->router->getCurrentRoute()->getName();
336
    }
337
338
    /**
339
     * Return current url
340
     *
341
     * @return string
342
     */
343
    protected function getUrl()
344
    {
345
        if ( ! $this->request)
346
        {
347
            return null;
348
        }
349
350
        $url = $this->request->path();
351
352
        if ( ! starts_with($url, '/'))
353
        {
354
            $url = '/' . $url;
355
        }
356
357
        return $url;
358
    }
359
360
    /**
361
     * @return array|null
362
     */
363 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...
364
    {
365
        $enabled = $this->app['config']->get('understand-laravel.query_string_enabled');
366
367
        if ( ! $enabled)
368
        {
369
            return null;
370
        }
371
372
        if ( ! $this->request->query instanceof \IteratorAggregate)
373
        {
374
            return null;
375
        }
376
377
        $queryString = [];
378
379
        foreach($this->request->query as $key => $value)
380
        {
381
            try
382
            {
383
                $queryString[$key] = $this->parseRequestFieldValue($key, $value);
384
            }
385
            catch (\Exception $e)
386
            {
387
                $queryString[$key] = '[handler error]';
388
            }
389
        }
390
391
        return $queryString;
392
    }
393
394
    /**
395
     * @return array|null
396
     */
397 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...
398
    {
399
        $enabled = $this->app['config']->get('understand-laravel.post_data_enabled');
400
401
        if ( ! $enabled)
402
        {
403
            return null;
404
        }
405
406
        if ( ! $this->request->request instanceof \IteratorAggregate)
407
        {
408
            return null;
409
        }
410
411
        $postData = [];
412
413
        foreach($this->request->request as $key => $value)
414
        {
415
            try
416
            {
417
                $postData[$key] = $this->parseRequestFieldValue($key, $value);
418
            }
419
            catch (\Exception $e)
420
            {
421
                $postData[$key] = '[handler error]';
422
            }
423
        }
424
425
        return $postData;
426
    }
427
428
    /**
429
     * @param $key
430
     * @param $value
431
     * @return mixed|string
432
     */
433
    protected function parseRequestFieldValue($key, $value)
434
    {
435
        $hiddenFields = $this->app['config']->get('understand-laravel.hidden_fields', []);
436
437
        if (in_array($key, $hiddenFields))
438
        {
439
            return '[value hidden]';
440
        }
441
442
        if (is_scalar($value))
443
        {
444
            return $value;
445
        }
446
447
        if (is_array($value))
448
        {
449
            return print_r($value, true);
450
        }
451
452
        if (is_object($value))
453
        {
454
            return get_class($value);
455
        }
456
457
        return (string)$value;
458
    }
459
460
    /**
461
     * Return request method
462
     *
463
     * @return string
464
     */
465
    protected function getRequestMethod()
466
    {
467
        if ( ! $this->request)
468
        {
469
            return null;
470
        }
471
472
        return $this->request->method();
473
    }
474
475
    /**
476
     * Return server ip address
477
     *
478
     * @return string
479
     */
480
    protected function getServerIp()
481
    {
482
        if ( ! $this->request)
483
        {
484
            return null;
485
        }
486
487
        return $this->request->server->get('SERVER_ADDR');
488
    }
489
490
    /**
491
     * Return client ip
492
     *
493
     * @return string
494
     */
495
    protected function getClientIp()
496
    {
497
        if ( ! $this->request)
498
        {
499
            return null;
500
        }
501
502
        return $this->request->getClientIp();
503
    }
504
505
    /**
506
     * Return client user agent string
507
     *
508
     * @return string
509
     */
510
    protected function getClientUserAgent()
511
    {
512
        if ( ! $this->request)
513
        {
514
            return null;
515
        }
516
517
        return $this->request->server->get('HTTP_USER_AGENT');
518
    }
519
520
    /**
521
     * Return current enviroment
522
     *
523
     * @return string
524
     */
525
    protected function getEnvironment()
526
    {
527
        return $this->environment;
528
    }
529
530
    /**
531
     * Retrive parameter from current session
532
     *
533
     * @param string $key
534
     * @return string
535
     */
536
    protected function getFromSession($key)
537
    {
538
        if ( ! $this->session)
539
        {
540
            return null;
541
        }
542
543
        return $this->session->get($key);
544
    }
545
546
    /**
547
     * Return group id
548
     *
549
     * @param array $log
550
     * @return string
551
     */
552
    protected function getGroupId(array $log)
553
    {
554
        $parts = [];
555
556
        foreach(['class', 'file', 'line', 'code'] as $field)
557
        {
558
            // only include `code` if it's not null value
559
            // the `code` attribute of the exception object is useful to differentiate SQL and other exceptions
560
            //
561
            // https://www.php.net/manual/en/exception.getcode.php
562
            // https://www.php.net/manual/en/pdo.errorinfo.php
563
            // https://docs.oracle.com/cd/E15817_01/appdev.111/b31228/appd.htm
564
            if ($field == 'code' && empty($log[$field]))
565
            {
566
                continue;
567
            }
568
569
            $parts[] = isset($log[$field]) ? (string)$log[$field] : null;
570
        }
571
572
        return sha1(implode('#', $parts));
573
    }
574
575
    /**
576
     * Return current active user id
577
     *
578
     * @return int
579
     */
580
    protected function getUserId()
581
    {
582
        try
583
        {
584
            if (class_exists('\Auth') && ($userId = \Auth::id()))
585
            {
586
                return $userId;
587
            }
588
        }
589
        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...
590
        {}
591
        catch (\Exception $e)
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
592
        {}
593
594
        try
595
        {
596
            if (class_exists('\Sentinel') && ($user = \Sentinel::getUser()))
597
            {
598
                return $user->id;
599
            }
600
        }
601
        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...
602
        {}
603
        catch (\Exception $e)
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
604
        {}
605
606
        try
607
        {
608
            if (class_exists('\Sentry') && ($user = \Sentry::getUser()))
609
            {
610
                return $user->id;
611
            }
612
        }
613
        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...
614
        {}
615
        catch (\Exception $e)
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
616
        {}
617
    }
618
619
    /**
620
     * @return string
621
     */
622
    protected function getArtisanCommandName()
623
    {
624
        if ($this->app->runningInConsole() && isset($_SERVER['argv']))
625
        {
626
            return implode(' ', $_SERVER['argv']);
627
        }
628
    }
629
630
    /**
631
     * @return bool
632
     */
633
    protected function getRunningInConsole()
634
    {
635
        return $this->app->runningInConsole();
636
    }
637
638
    /**
639
     * @return float
640
     */
641
    protected function getLoggerVersion()
642
    {
643
        return Logger::VERSION;
644
    }
645
646
    /**
647
     * Return process identifier token
648
     *
649
     * @return string
650
     */
651
    protected function getProcessIdentifier()
652
    {
653
        return $this->tokenProvider->getToken();
654
    }
655
656
}
657