Issues (28)

src/Actions/ParseTraffic.php (2 issues)

Labels
Severity
1
<?php
2
3
namespace Sfneal\Tracking\Actions;
4
5
use Illuminate\Http\RedirectResponse;
6
use Illuminate\Http\Request;
7
use Illuminate\Http\Response;
8
use Illuminate\Support\Facades\Cookie;
9
use Jenssegers\Agent\Agent;
10
use Sfneal\Actions\Action;
11
use Sfneal\Helpers\Arrays\ArrayHelpers;
12
use Sfneal\Helpers\Laravel\AppInfo;
13
14
class ParseTraffic extends Action
15
{
16
    /**
17
     * Array keys to exclude from the 'request_payload' attribute.
18
     *
19
     * @var array
20
     */
21
    private const REQUEST_PAYLOAD_EXCLUSIONS = [
22
        '_token',
23
        '_method',
24
        'password',
25
    ];
26
27
    /**
28
     * @var array
29
     */
30
    private $tracking = [];
31
32
    /**
33
     * @var Request
34
     */
35
    private $request;
36
    /**
37
     * @var Response|RedirectResponse
38
     */
39
    private $response;
40
41
    /**
42
     * @var string
43
     */
44
    private $timestamp;
45
46
    /**
47
     * Create a new event instance.
48
     *
49
     * @param  Request  $request
50
     * @param  Response|RedirectResponse  $response
51
     * @param  string|null  $timestamp
52
     */
53
    public function __construct(Request $request, $response, string $timestamp = null)
54
    {
55
        $this->request = $request;
56
        $this->response = $response;
57
        $this->timestamp = $timestamp ?? microtime();
58
    }
59
60
    /**
61
     * Execute the action.
62
     *
63
     * @return array
64
     */
65
    public function execute(): array
66
    {
67
        // Initialize event for serialization
68
        $this->tracking['user_id'] = intval(auth()->id());
69
        $this->tracking['session_id'] = Cookie::get(config('session.cookie'));
70
        $this->tracking['app_version'] = AppInfo::version();
71
        $this->tracking['time_stamp'] = self::getTimestamp($this->timestamp);
72
73
        // Request data
74
        $this->tracking['request'] = $this->parseRequest();
75
76
        // Response data
77
        $this->tracking['response'] = $this->parseResponse();
78
79
        // Request data
80
        $this->tracking['agent'] = $this->parseAgent();
81
82
        return $this->tracking;
83
    }
84
85
    /**
86
     * Parse a Request object to retrieve relevant data.
87
     *
88
     * @return array
89
     */
90
    public function parseRequest(): array
91
    {
92
        return [
93
            'host' => $this->request->getHttpHost(),
94
            'uri' => $this->request->getRequestUri(),
95
            'method' => $this->request->getMethod(),
96
            'payload' => $this->getRequestPayload(),
97
            'browser' => $_SERVER['HTTP_USER_AGENT'] ?? null,
98
            'ip' => $this->request->ip(),
99
            'referrer' => $_SERVER['HTTP_REFERER'] ?? null,
100
            'token' => $this->request->get('track_traffic_token') ?? uniqid(),
101
        ];
102
    }
103
104
    /**
105
     * Parse a Response object to retrieve relevant data.
106
     *
107
     * @return array
108
     */
109
    public function parseResponse(): array
110
    {
111
        // Status code & response time
112
        $response = [
113
            'code' => $this->response->getStatusCode(),
114
            'time' => self::getResponseTime($this->timestamp),
115
        ];
116
117
        // Store response content served if enabled
118
        if (config('tracking.traffic.response_content')) {
119
            $response['content'] = $this->response->getContent();
120
        }
121
122
        return $response;
123
    }
124
125
    /**
126
     * Set user agent data on platform, device & browser.
127
     *
128
     * @return array
129
     */
130
    public function parseAgent(): array
131
    {
132
        $agent = new Agent();
133
134
        return [
135
            'platform' => $agent->platform(),
136
            'device' => $agent->device(),
137
            'browser' => $agent->browser(),
138
        ];
139
    }
140
141
    /**
142
     * Retrieve a request payload with exclusions removed.
143
     *
144
     * @return array
145
     */
146
    private function getRequestPayload(): array
147
    {
148
        return ArrayHelpers::from($this->request->query())
0 ignored issues
show
It seems like $this->request->query() can also be of type null and string; however, parameter $array of Sfneal\Helpers\Arrays\ArrayHelpers::from() 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

148
        return ArrayHelpers::from(/** @scrutinizer ignore-type */ $this->request->query())
Loading history...
149
            ->merge($this->request->input())
150
            ->removeKeys(self::REQUEST_PAYLOAD_EXCLUSIONS)
151
            ->get();
152
    }
153
154
    /**
155
     * Determine the amount of time taken to return a response.
156
     *
157
     * @param  string  $timestamp
158
     * @return float
159
     */
160
    private static function getResponseTime(string $timestamp): float
161
    {
162
        return floatval(number_format($timestamp - LARAVEL_START, 2));
163
    }
164
165
    /**
166
     * Retrieve a traffic visit occurred at timestamp.
167
     *
168
     * @param  string  $timestamp
169
     * @return string
170
     */
171
    private static function getTimestamp(string $timestamp): string
172
    {
173
        return date('Y-m-d H:i:s', $timestamp);
0 ignored issues
show
$timestamp of type string is incompatible with the type integer|null expected by parameter $timestamp of date(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

173
        return date('Y-m-d H:i:s', /** @scrutinizer ignore-type */ $timestamp);
Loading history...
174
    }
175
}
176