Skip to content

Commit 1555651

Browse files
committed
Merge branch 'main' of github.com:hexydec/agentzero into main
2 parents 02ed305 + ad6d852 commit 1555651

File tree

13 files changed

+175
-74
lines changed

13 files changed

+175
-74
lines changed

README.md

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ The returned value will be something like:
6060
public readonly ?string 'browser' => string 'Chrome';
6161
public readonly ?string 'browserversion' => string '116.0.0.0';
6262
public readonly ?string 'browserstatus' => 'previous';
63-
public readonly ?string 'browserreleased' => '2023-09-15';
64-
public readonly ?string 'browserlatest' => '133.0.6943.54';
63+
public readonly ?string 'browserreleased' => '2023-09-15';
64+
public readonly ?string 'browserlatest' => '133.0.6943.54';
6565
public readonly ?string 'language' => string 'en-GB';
6666

6767
// app
@@ -77,16 +77,53 @@ The returned value will be something like:
7777
public readonly ?string 'proxy' => null;
7878

7979
// screen
80-
public readonly ?int 'width' => int 1080
81-
public readonly ?int 'height' => int 2116
82-
public readonly ?int 'dpi' => int 420
80+
public readonly ?int 'width' => int 1080;
81+
public readonly ?int 'height' => int 2116;
82+
public readonly ?int 'dpi' => int 420;
8383
public readonly ?float 'density' => null;
8484
public readonly ?bool 'darkmode' => null;;
8585
);
8686
```
8787

8888
You can read the [full list of properties here](docs/api.md).
8989

90+
### Client Hints
91+
92+
AgentZero now supports processing client hints for improved user-agent information. You must request the client hints to improve the information delivered through the user-agent string:
93+
94+
```php
95+
96+
// request client hints
97+
\header('Accept-CH: Width, ECT, Device-Memory, Sec-CH-UA-Platform-Version, Sec-CH-UA-Model, Sec-CH-UA-Full-Version-List');
98+
99+
// retrieve client hints
100+
$hints = \hexydec\agentzero\agentzero::getHints();
101+
102+
// parse
103+
$az = \hexydec\agentzero\agentzero::parse($_SERVER['HTTP_USER_AGENT'], $hints);
104+
```
105+
106+
Note that by using the `Accept-CH` header, you may receive client hints on subsequent requests, if you need the client hints on first call, use the `Critical-CH` header instead (Warning: This will cause an extra round trip as the browser must re-request the first page).
107+
108+
### Browser Versions
109+
110+
You can determine the date the browser was released, latest version, and status, by setting where the version file should be cached:
111+
112+
```php
113+
$config = [
114+
'versionscache' => __DIR__.'/cache/versions.json'
115+
];
116+
$az = \hexydec\agentzero\agentzero::parse($_SERVER['HTTP_USER_AGENT'], [], $config);
117+
var_dump(
118+
$ua->browserstatus, // either "canary", "beta", "latest", "previous", "legacy", legacy means released over 5 years ago
119+
$ua->browserreleased, // the date the browser was released
120+
$us->browserlatest // the latest version number of the browser
121+
);
122+
123+
```
124+
125+
The browser version information is sourced from [my browser versions project](https://github.com/hexydec/versions).
126+
90127
## Supported Features
91128

92129
AgentZero supports a wide range of architectures, browsers, rendering engines, platforms, devices, languages, and crawlers. [Access the full list on the Supported Features page](docs/support.md).

composer.lock

Lines changed: 14 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

index.php

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,29 @@
11
<?php
2+
3+
use hexydec\agentzero\agentzero;
4+
25
require(__DIR__.'/src/autoload.php');
36

47
// fetch UA string
58
$ua = $_POST['ua'] ?? $_SERVER['HTTP_USER_AGENT'] ?? '';
69

710
// client hints
8-
$hints = [
9-
'sec-ch-ua-mobile' => $_POST['mobile'] ?? $_SERVER['HTTP_SEC_CH_UA_MOBILE'] ?? '',
10-
'sec-ch-ua-full-version-list' => $_POST['browser'] ?? $_SERVER['HTTP_SEC_CH_UA_FULL_VERSION_LIST'] ?? '',
11-
'sec-ch-ua-platform' => $_POST['platform'] ?? $_SERVER['HTTP_SEC_CH_UA_PLATFORM'] ?? '',
12-
'sec-ch-ua-platform-version' => $_POST['platformversion'] ?? $_SERVER['HTTP_SEC_CH_UA_PLATFORM_VERSION'] ?? '',
13-
'sec-ch-ua-model' => $_POST['model'] ?? $_SERVER['HTTP_SEC_CH_UA_MODEL'] ?? '',
14-
'device-memory' => $_POST['memory'] ?? $_SERVER['HTTP_DEVICE_MEMORY'] ?? '',
15-
'width' => $_POST['width'] ?? $_SERVER['HTTP_WIDTH'] ?? '',
16-
'ect' => $_POST['ect'] ?? $_SERVER['HTTP_ECT'] ?? ''
11+
$hints = agentzero::getHints();
12+
$keys = [
13+
'sec-ch-ua-mobile',
14+
'sec-ch-ua-full-version-list',
15+
'sec-ch-ua-platform',
16+
'sec-ch-ua-platform-version',
17+
'sec-ch-ua-model',
18+
'device-memory',
19+
'width',
20+
'ect'
1721
];
22+
foreach ($keys AS $item) {
23+
if (!empty($_POST[$item])) {
24+
$hints[$item] = $_POST[$item];
25+
}
26+
}
1827
$memsizes = [
1928
'0.25' => '256Mb',
2029
'0.5' => '512Mb',
@@ -39,7 +48,7 @@
3948

4049
// timing variables
4150
$time = \microtime(true);
42-
$output = \hexydec\agentzero\agentzero::parse($ua, \array_filter($hints));
51+
$output = \hexydec\agentzero\agentzero::parse($ua, \array_filter($hints), ['versionscache' => __DIR__.'/cache/versions.json']);
4352
$total = \microtime(true) - $time;
4453
?>
4554
<!DOCTYPE html>
@@ -104,48 +113,48 @@
104113
<h3>Client Hints</h3>
105114
<div class="form__control">
106115
<label class="form__label">Mobile:</label>
107-
<select name="mobile">
116+
<select name="sec-ch-ua-mobile">
108117
<option value="">-- Select Mobile --</option>
109118
<?php foreach ($devices AS $key => $item) { ?>
110-
<option value="<?= \htmlspecialchars($key); ?>"<?= $hints['sec-ch-ua-mobile'] === $key ? ' selected="selected"' : ''; ?>><?= \htmlspecialchars($item); ?></option>
119+
<option value="<?= \htmlspecialchars($key); ?>"<?= ($hints['sec-ch-ua-mobile'] ?? null) === $key ? ' selected="selected"' : ''; ?>><?= \htmlspecialchars($item); ?></option>
111120
<?php } ?>
112121
</select>
113122
</div>
114123
<div class="form__control">
115124
<label class="form__label">Browser:</label>
116-
<input type="text" class="form__input" name="browser" value="<?= \htmlspecialchars($hints['sec-ch-ua-full-version-list']); ?>" />
125+
<input type="text" class="form__input" name="sec-ch-ua-full-version-list" value="<?= \htmlspecialchars($hints['sec-ch-ua-full-version-list'] ?? ''); ?>" />
117126
</div>
118127
<div class="form__control">
119128
<label class="form__label">Platform:</label>
120-
<input type="text" class="form__input--short" name="platform" value="<?= \htmlspecialchars($hints['sec-ch-ua-platform']); ?>" />
129+
<input type="text" class="form__input--short" name="sec-ch-ua-platform" value="<?= \htmlspecialchars($hints['sec-ch-ua-platform'] ?? ''); ?>" />
121130
</div>
122131
<div class="form__control">
123132
<label class="form__label">Platform Version:</label>
124-
<input type="text" class="form__input--short" name="platformversion" value="<?= \htmlspecialchars($hints['sec-ch-ua-platform-version']); ?>" />
133+
<input type="text" class="form__input--short" name="sec-ch-ua-platform-version" value="<?= \htmlspecialchars($hints['sec-ch-ua-platform-version'] ?? ''); ?>" />
125134
</div>
126135
<div class="form__control">
127136
<label class="form__label">Model:</label>
128-
<input type="text" class="form__input--short" name="model" value="<?= \htmlspecialchars($hints['sec-ch-ua-model']); ?>" />
137+
<input type="text" class="form__input--short" name="sec-ch-ua-model" value="<?= \htmlspecialchars($hints['sec-ch-ua-model'] ?? ''); ?>" />
129138
</div>
130139
<div class="form__control">
131140
<label class="form__label">Memory:</label>
132-
<select name="memory">
141+
<select name="device-memory">
133142
<option value="">-- Select Memory --</option>
134143
<?php foreach ($memsizes AS $key => $item) { ?>
135-
<option value="<?= \htmlspecialchars($key); ?>"<?= $hints['device-memory'] == $key ? ' selected="selected"' : ''; ?>><?= \htmlspecialchars($item); ?></option>
144+
<option value="<?= \htmlspecialchars($key); ?>"<?= ($hints['device-memory'] ?? null) == $key ? ' selected="selected"' : ''; ?>><?= \htmlspecialchars($item); ?></option>
136145
<?php } ?>
137146
</select>
138147
</div>
139148
<div class="form__control">
140149
<label class="form__label">Width:</label>
141-
<input type="number" class="form__input--short" name="width" value="<?= \htmlspecialchars($hints['width']); ?>" />
150+
<input type="number" class="form__input--short" name="width" value="<?= \htmlspecialchars($hints['width'] ?? ''); ?>" />
142151
</div>
143152
<div class="form__control">
144153
<label class="form__label">Connection:</label>
145154
<select name="ect">
146155
<option value="">-- Select Connection --</option>
147156
<?php foreach ($conns AS $key => $item) { ?>
148-
<option value="<?= \htmlspecialchars($key); ?>"<?= $hints['ect'] === $key ? ' selected="selected"' : ''; ?>><?= \htmlspecialchars($item); ?></option>
157+
<option value="<?= \htmlspecialchars($key); ?>"<?= ($hints['ect'] ?? null) === $key ? ' selected="selected"' : ''; ?>><?= \htmlspecialchars($item); ?></option>
149158
<?php } ?>
150159
</select>
151160
</div>

src/agentzero.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,32 @@ public function __get(string $key) : string|int|null {
145145
return $this->{$key} ?? null;
146146
}
147147

148+
/**
149+
* Fetch the client hints sent by the browser
150+
*
151+
* @return array<string,string> An array containing relevant client hints sent by the client
152+
*/
153+
public static function getHints() : array {
154+
$hints = [
155+
'sec-ch-ua-mobile',
156+
'sec-ch-ua-full-version-list',
157+
'sec-ch-ua-platform',
158+
'sec-ch-ua-platform-version',
159+
'sec-ch-ua-model',
160+
'device-memory',
161+
'width',
162+
'ect'
163+
];
164+
$data = [];
165+
foreach ($hints AS $item) {
166+
$upper = \strtoupper(\str_replace('-', '_', $item));
167+
if (!empty($_SERVER['HTTP_'.$upper])) {
168+
$data[$item] = $_SERVER['HTTP_'.$upper];
169+
}
170+
}
171+
return $data;
172+
}
173+
148174
/**
149175
* Extracts tokens from a UA string
150176
*

src/config.php

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,10 @@ public static function get(array $config = []) : ?array {
3030
apps::get(),
3131
frameworks::get()
3232
),
33-
'versions' => [
34-
'source' => 'https://raw.githubusercontent.com/hexydec/versions/refs/heads/main/dist/versions.json', // browser version data source
35-
'cache' => \dirname(__DIR__).'/cache/versions.json', // location of the cache file
36-
'cachelife' => 604800, // how long to cache for
37-
'currentdate' => null // the point in time to calculate the browser data from, may be in the past (DateTime object)
38-
]
33+
'versionssource' => 'https://raw.githubusercontent.com/hexydec/versions/refs/heads/main/dist/versions.json', // browser version data source
34+
'versionscache' => null, // location of the cache file, null to not fetch version data
35+
'versionscachelife' => 604800, // how long to cache for
36+
'currentdate' => null // the point in time to calculate the browser data from, may be in the past (DateTime object)
3937
];
4038
}
4139
return \array_replace_recursive($default, $config);

src/helpers/hints.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,20 @@
44

55
class hints {
66

7+
/**
8+
* Parses client hints to set agentzero properties
9+
*
10+
* @param string &$ua A reference to the User-Agent string, which may be used with brand names and versions
11+
* @param array $hints An array of client hints
12+
* @return stdClass A stdClass object containing parsed values for agentzero
13+
*/
714
public static function parse(string &$ua, array $hints) : \stdClass {
815
$map = [
916
'sec-ch-ua-mobile' => fn (\stdClass $obj, string $value) : string => $obj->category = $value === '?1' ? 'mobile' : 'desktop',
1017
'sec-ch-ua-platform' => fn (\stdClass $obj, string $value) : ?string => $obj->platform = \trim($value, '"') ?: null,
1118
'sec-ch-ua-platform-version' => function (\stdClass $obj, string $value) : void {
1219
$value = \trim($value, '"');
13-
if ($obj->platform === 'Windows') {
20+
if (($obj->platform ?? null) === 'Windows') {
1421
$map = [
1522
'8',
1623
'10.1507',

0 commit comments

Comments
 (0)