Skip to content

Commit 402c0bb

Browse files
committed
Added Http Collector
1 parent 099ef54 commit 402c0bb

File tree

2 files changed

+683
-0
lines changed

2 files changed

+683
-0
lines changed
Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
<?php
2+
3+
namespace Barryvdh\Debugbar\DataCollector;
4+
5+
use DebugBar\DataCollector\DataCollector;
6+
use DebugBar\DataCollector\Renderable;
7+
use Illuminate\Database\Eloquent\Model;
8+
use Illuminate\Http\Request;
9+
use Illuminate\Http\Response as IlluminateResponse;
10+
use Illuminate\Support\Arr;
11+
use Illuminate\Support\Str;
12+
use Illuminate\View\View;
13+
use Symfony\Component\HttpFoundation\RedirectResponse;
14+
use Symfony\Component\HttpFoundation\Response;
15+
16+
class HttpCollector extends DataCollector implements Renderable
17+
{
18+
/** @var Request */
19+
protected $request;
20+
21+
/** @var Response */
22+
protected $response;
23+
24+
/** @var float */
25+
protected $startTime;
26+
27+
/** @var array */
28+
protected $hiddenRequestHeaders;
29+
30+
/** @var array */
31+
protected $hiddenParameters;
32+
33+
/** @var array */
34+
protected $hiddenResponseParameters;
35+
36+
/** @var array */
37+
protected $ignoredStatusCodes;
38+
39+
/** @var int */
40+
protected $sizeLimit;
41+
42+
/**
43+
* Create a new HttpCollector
44+
*
45+
* @param Request $request
46+
* @param Response $response
47+
* @param float|null $startTime
48+
* @param array $hiddenRequestHeaders
49+
* @param array $hiddenParameters
50+
* @param array $hiddenResponseParameters
51+
* @param array $ignoredStatusCodes
52+
* @param int $sizeLimit Size limit in KB (default: 64)
53+
*/
54+
public function __construct(
55+
Request $request,
56+
Response $response,
57+
$startTime = null,
58+
array $hiddenRequestHeaders = [],
59+
array $hiddenParameters = [],
60+
array $hiddenResponseParameters = [],
61+
array $ignoredStatusCodes = [],
62+
int $sizeLimit = 64
63+
) {
64+
$this->request = $request;
65+
$this->response = $response;
66+
$this->startTime = $startTime ?? (defined('LARAVEL_START') ? LARAVEL_START : $request->server->get('REQUEST_TIME_FLOAT'));
67+
$this->hiddenRequestHeaders = $hiddenRequestHeaders;
68+
$this->hiddenParameters = $hiddenParameters;
69+
$this->hiddenResponseParameters = $hiddenResponseParameters;
70+
$this->ignoredStatusCodes = $ignoredStatusCodes;
71+
$this->sizeLimit = $sizeLimit;
72+
}
73+
74+
/**
75+
* {@inheritDoc}
76+
*/
77+
public function getName()
78+
{
79+
return 'http';
80+
}
81+
82+
/**
83+
* {@inheritDoc}
84+
*/
85+
public function collect()
86+
{
87+
$uri = str_replace($this->request->root(), '', $this->request->fullUrl()) ?: '/';
88+
$statusCode = $this->response->getStatusCode();
89+
$method = $this->request->method();
90+
91+
// Check if status code should be ignored
92+
if (in_array($statusCode, $this->ignoredStatusCodes)) {
93+
return [];
94+
}
95+
96+
return [
97+
'title' => "$uri returned HTTP Status Code $statusCode",
98+
'description' => "$uri for $method request returned HTTP Status Code $statusCode",
99+
'uri' => $uri,
100+
'method' => $method,
101+
'controller_action' => optional($this->request->route())->getActionName(),
102+
'middleware' => array_values(optional($this->request->route())->gatherMiddleware() ?? []),
103+
'headers' => $this->formatHeaders($this->request->headers->all()),
104+
'payload' => $this->formatPayload($this->extractInput($this->request)),
105+
'session' => $this->formatPayload($this->extractSessionVariables($this->request)),
106+
'response_status' => $statusCode,
107+
'response' => $this->formatResponse($this->response),
108+
'duration' => $this->startTime ? floor((microtime(true) - $this->startTime) * 1000) : null,
109+
'memory' => round(memory_get_peak_usage(true) / 1024 / 1024, 1),
110+
];
111+
}
112+
113+
/**
114+
* {@inheritDoc}
115+
*/
116+
public function getWidgets()
117+
{
118+
return [
119+
'http' => [
120+
'icon' => 'globe',
121+
'widget' => 'PhpDebugBar.Widgets.HtmlVariableListWidget',
122+
'map' => 'http',
123+
'default' => '{}',
124+
],
125+
'http:badge' => [
126+
'map' => 'http.response_status',
127+
'default' => 'null',
128+
],
129+
];
130+
}
131+
132+
/**
133+
* Format the given headers.
134+
*
135+
* @param array $headers
136+
* @return array
137+
*/
138+
protected function formatHeaders(array $headers)
139+
{
140+
$headers = collect($headers)->map(function ($header) {
141+
return $header[0] ?? $header;
142+
})->toArray();
143+
144+
return $this->hideParameters($headers, $this->hiddenRequestHeaders);
145+
}
146+
147+
/**
148+
* Format the given payload.
149+
*
150+
* @param array $payload
151+
* @return array
152+
*/
153+
protected function formatPayload(array $payload)
154+
{
155+
return $this->hideParameters($payload, $this->hiddenParameters);
156+
}
157+
158+
/**
159+
* Hide the given parameters.
160+
*
161+
* @param array $data
162+
* @param array $hidden
163+
* @return array
164+
*/
165+
protected function hideParameters(array $data, array $hidden)
166+
{
167+
foreach ($hidden as $parameter) {
168+
if (Arr::get($data, $parameter)) {
169+
Arr::set($data, $parameter, '********');
170+
}
171+
}
172+
173+
return $data;
174+
}
175+
176+
/**
177+
* Extract the session variables from the given request.
178+
*
179+
* @param Request $request
180+
* @return array
181+
*/
182+
protected function extractSessionVariables(Request $request)
183+
{
184+
return $request->hasSession() ? $request->session()->all() : [];
185+
}
186+
187+
/**
188+
* Extract the input from the given request.
189+
*
190+
* @param Request $request
191+
* @return array
192+
*/
193+
protected function extractInput(Request $request)
194+
{
195+
$files = $request->files->all();
196+
197+
array_walk_recursive($files, function (&$file) {
198+
$file = [
199+
'name' => $file->getClientOriginalName(),
200+
'size' => $file->isFile() ? ($file->getSize() / 1000) . 'KB' : '0',
201+
];
202+
});
203+
204+
return array_replace_recursive($request->input(), $files);
205+
}
206+
207+
/**
208+
* Format the given response object.
209+
*
210+
* @param Response $response
211+
* @return array|string
212+
*/
213+
protected function formatResponse(Response $response)
214+
{
215+
$content = $response->getContent();
216+
217+
if (is_string($content)) {
218+
// Handle JSON responses
219+
if (is_array(json_decode($content, true)) && json_last_error() === JSON_ERROR_NONE) {
220+
return $this->contentWithinLimits($content)
221+
? $this->hideParameters(json_decode($content, true), $this->hiddenResponseParameters)
222+
: 'Purged By Debugbar (Response too large)';
223+
}
224+
225+
// Handle plain text responses
226+
if (Str::startsWith(strtolower($response->headers->get('Content-Type') ?? ''), 'text/plain')) {
227+
return $this->contentWithinLimits($content) ? $content : 'Purged By Debugbar (Response too large)';
228+
}
229+
}
230+
231+
// Handle redirect responses
232+
if ($response instanceof RedirectResponse) {
233+
return 'Redirected to ' . $response->getTargetUrl();
234+
}
235+
236+
// Handle view responses
237+
if ($response instanceof IlluminateResponse && $response->getOriginalContent() instanceof View) {
238+
return [
239+
'view' => $response->getOriginalContent()->getPath(),
240+
'data' => $this->extractDataFromView($response->getOriginalContent()),
241+
];
242+
}
243+
244+
return 'HTML Response';
245+
}
246+
247+
/**
248+
* Determine if the content is within the set limits.
249+
*
250+
* @param string $content
251+
* @return bool
252+
*/
253+
protected function contentWithinLimits($content)
254+
{
255+
return mb_strlen($content) / 1000 <= $this->sizeLimit;
256+
}
257+
258+
/**
259+
* Extract the data from the given view in array form.
260+
*
261+
* @param View $view
262+
* @return array
263+
*/
264+
protected function extractDataFromView(View $view)
265+
{
266+
return collect($view->getData())->map(function ($value) {
267+
if ($value instanceof Model) {
268+
return $this->formatModel($value);
269+
} elseif (is_object($value)) {
270+
return [
271+
'class' => get_class($value),
272+
'properties' => json_decode(json_encode($value), true),
273+
];
274+
} else {
275+
return json_decode(json_encode($value), true);
276+
}
277+
})->toArray();
278+
}
279+
280+
/**
281+
* Format a model instance.
282+
*
283+
* @param Model $model
284+
* @return array
285+
*/
286+
protected function formatModel(Model $model)
287+
{
288+
return [
289+
'class' => get_class($model),
290+
'key' => $model->getKey(),
291+
'attributes' => $model->getAttributes(),
292+
'relations' => collect($model->getRelations())->map(function ($relation) {
293+
if ($relation instanceof Model) {
294+
return [
295+
'class' => get_class($relation),
296+
'key' => $relation->getKey(),
297+
];
298+
}
299+
return gettype($relation);
300+
})->toArray(),
301+
];
302+
}
303+
}

0 commit comments

Comments
 (0)