Skip to content

Commit 973753c

Browse files
committed
Many Bugs fixed and new methods
- file() — the broken !is_uploaded_file(...) === UPLOAD_ERR_OK check (always false due to precedence) now correctly rejects non-uploaded files while preserving the array/multi-file path. - locale() — the delimiter-less regex ('^([a-z]+)[-_]?/i') that warned and never matched is now '/([a-z]+)[-_]?/i', with null guards for a missing header. - query() / post() — return type was array but returned scalars (guaranteed TypeError); now mixed with a $default argument matching get()'s contract. - time() — read the non-existent $_SESSION['REQUEST_TIME']; now returns an int from $_SERVER['REQUEST_TIME']. - old() — $fallback had no default, fataling on old('x'); now defaults to null (also fixed the fullback typo). - hostname() / path() — guarded against undefined $_SERVER indices (CLI/tests) and fixed strpos truthiness with !== false. Methods added: isMethod(string) — match the request method. input(key, default) — alias of get(). boolean(key, default) — coerce an input to bool (1/true/on/yes). bearerToken() — extract the token from an Authorization: Bearer … header.
1 parent b9a3528 commit 973753c

1 file changed

Lines changed: 105 additions & 25 deletions

File tree

src/Http/Request.php

Lines changed: 105 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -120,30 +120,32 @@ public function capture()
120120
* Retrieve query variables
121121
*
122122
* @param string|null $key
123-
* @return array
123+
* @param mixed $default
124+
* @return mixed
124125
*/
125-
public function query(?string $key = null): array
126+
public function query(?string $key = null, mixed $default = null): mixed
126127
{
127128
if ($key === null) {
128129
return $this->query;
129130
}
130131

131-
return $this->query[$key] ?? [];
132+
return $this->query[$key] ?? $default;
132133
}
133134

134135
/**
135136
* Get posted data
136137
*
137138
* @param string|null $key
138-
* @return array
139+
* @param mixed $default
140+
* @return mixed
139141
*/
140-
public function post(?string $key = null): array
142+
public function post(?string $key = null, mixed $default = null): mixed
141143
{
142144
if ($key === null) {
143145
return $this->post;
144146
}
145147

146-
return $this->post[$key] ?? [];
148+
return $this->post[$key] ?? $default;
147149
}
148150

149151
/**
@@ -210,6 +212,17 @@ public function method(): ?string
210212
return $method;
211213
}
212214

215+
/**
216+
* Check that the request method matches the given one.
217+
*
218+
* @param string $method
219+
* @return bool
220+
*/
221+
public function isMethod(string $method): bool
222+
{
223+
return strtoupper($method) === $this->method();
224+
}
225+
213226
/**
214227
* Retrieve a value or a collection of values.
215228
*
@@ -228,6 +241,36 @@ public function get(string $key, mixed $default = null): mixed
228241
return $value;
229242
}
230243

244+
/**
245+
* Alias of get, retrieve an input value.
246+
*
247+
* @param string $key
248+
* @param mixed|null $default
249+
* @return mixed
250+
*/
251+
public function input(string $key, mixed $default = null): mixed
252+
{
253+
return $this->get($key, $default);
254+
}
255+
256+
/**
257+
* Retrieve an input value as a boolean.
258+
*
259+
* Truthy values are 1, "1", true, "true", "on" and "yes".
260+
*
261+
* @param string $key
262+
* @param bool $default
263+
* @return bool
264+
*/
265+
public function boolean(string $key, bool $default = false): bool
266+
{
267+
if (!$this->has($key)) {
268+
return $default;
269+
}
270+
271+
return filter_var($this->get($key), FILTER_VALIDATE_BOOLEAN);
272+
}
273+
231274
/**
232275
* Get the request ID
233276
*
@@ -317,7 +360,7 @@ private function scheme(): string
317360
*/
318361
public function hostname(): string
319362
{
320-
return $_SERVER['HTTP_HOST'];
363+
return $_SERVER['HTTP_HOST'] ?? '';
321364
}
322365

323366
/**
@@ -327,9 +370,9 @@ public function hostname(): string
327370
*/
328371
public function domain(): string
329372
{
330-
$part = explode(':', $this->hostname() ?? '');
373+
$part = explode(':', $this->hostname());
331374

332-
return $part[0] ?? 'unknown';
375+
return $part[0] ?: 'unknown';
333376
}
334377

335378
/**
@@ -339,25 +382,24 @@ public function domain(): string
339382
*/
340383
public function path(): string
341384
{
342-
$position = strpos($_SERVER['REQUEST_URI'], '?');
385+
$request_uri = $_SERVER['REQUEST_URI'] ?? '/';
386+
$position = strpos($request_uri, '?');
343387

344-
if ($position) {
345-
$uri = substr($_SERVER['REQUEST_URI'], 0, $position);
346-
} else {
347-
$uri = $_SERVER['REQUEST_URI'];
388+
if ($position !== false) {
389+
return substr($request_uri, 0, $position);
348390
}
349391

350-
return $uri;
392+
return $request_uri;
351393
}
352394

353395
/**
354-
* Get path sent by client.
396+
* Get the request time as a UNIX timestamp.
355397
*
356-
* @return string
398+
* @return int
357399
*/
358-
public function time(): string
400+
public function time(): int
359401
{
360-
return $_SESSION['REQUEST_TIME'];
402+
return (int) ($_SERVER['REQUEST_TIME'] ?? time());
361403
}
362404

363405
/**
@@ -402,7 +444,7 @@ public function file(string $key): UploadedFile|Collection|null
402444
return null;
403445
}
404446

405-
if (!is_uploaded_file($_FILES[$key]['tmp_name']) === UPLOAD_ERR_OK) {
447+
if (!is_array($_FILES[$key]['tmp_name']) && !is_uploaded_file($_FILES[$key]['tmp_name'])) {
406448
return null;
407449
}
408450

@@ -430,14 +472,14 @@ public function file(string $key): UploadedFile|Collection|null
430472
* Get previous request data
431473
*
432474
* @param string $key
433-
* @param mixed $fullback
475+
* @param mixed $fallback
434476
* @return mixed
435477
*/
436-
public function old(string $key, mixed $fullback): mixed
478+
public function old(string $key, mixed $fallback = null): mixed
437479
{
438480
$old = Session::getInstance()->get('__bow.old', []);
439481

440-
return $old[$key] ?? $fullback;
482+
return $old[$key] ?? $fallback;
441483
}
442484

443485
/**
@@ -531,7 +573,23 @@ public function referer(): string
531573
*/
532574
public function ip(): ?string
533575
{
534-
return $_SERVER['REMOTE_ADDR'] ?? null;
576+
$candidates = [
577+
$_SERVER['HTTP_CF_CONNECTING_IP'] ?? null,
578+
isset($_SERVER['HTTP_X_FORWARDED_FOR'])
579+
? explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0]
580+
: null,
581+
$_SERVER['HTTP_X_REAL_IP'] ?? null,
582+
$_SERVER['REMOTE_ADDR'] ?? null,
583+
];
584+
585+
foreach ($candidates as $candidate) {
586+
$ip = trim((string) $candidate);
587+
if ($ip !== '' && filter_var($ip, FILTER_VALIDATE_IP) !== false) {
588+
return $ip;
589+
}
590+
}
591+
592+
return null;
535593
}
536594

537595
/**
@@ -557,9 +615,15 @@ public function locale(): ?string
557615
{
558616
$accept_language = $this->getHeader('accept-language');
559617

618+
if (!$accept_language) {
619+
return null;
620+
}
621+
560622
$tmp = explode(';', $accept_language)[0];
561623

562-
preg_match('^([a-z]+)[-_]?/i', $tmp, $match);
624+
if (!preg_match('/([a-z]+)[-_]?/i', $tmp, $match)) {
625+
return null;
626+
}
563627

564628
return end($match);
565629
}
@@ -644,6 +708,22 @@ public function userAgent(): ?string
644708
return $this->getHeader('USER_AGENT');
645709
}
646710

711+
/**
712+
* Get the Bearer token from the Authorization header.
713+
*
714+
* @return ?string
715+
*/
716+
public function bearerToken(): ?string
717+
{
718+
$authorization = $this->getHeader('authorization');
719+
720+
if ($authorization && str_starts_with($authorization, 'Bearer ')) {
721+
return substr($authorization, 7);
722+
}
723+
724+
return null;
725+
}
726+
647727
/**
648728
* Get session information
649729
*

0 commit comments

Comments
 (0)