This example demonstrates device detection using User-Agent Client Hints on a website.
This example demonstrates device detection using User-Agent Client Hints on a website. When a browser that supports User-Agent Client Hints first visits a website, the server receives the sec-ch-ua and sec-ch-ua-mobile headers along with the user-agent header. The server uses these headers to determine whether the browser supports User-Agent Client Hints. It can request additional hints by setting the Accept-CH response header. Clicking the button below will cause a new request to be sent to the server, along with any additional headers that have been requested.
In this example we create an on premise 51Degrees device detection pipeline, in order to do this you will need a copy of the 51Degrees on-premise library and need to make the following additions to your php.ini file
When running under a process manager such as Apache MPM or php-fpm, the engine must load the whole data file into memory. This is now enforced automatically (the MaxPerformance profile is always used), so no extra configuration is required. More details can be found in README.
<?php
require __DIR__ . '/../../vendor/autoload.php';
$assets = [
'/css/examples-main.min.css' => ['static/css/examples-main.min.css', 'text/css'],
'/js/examples.min.js' => ['static/js/examples.min.js', 'application/javascript']
];
$requestPath = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH);
if (isset($assets[$requestPath])) {
[$relativePath, $contentType] = $assets[$requestPath];
$assetFile = __DIR__ . '/' . $relativePath;
if (is_file($assetFile)) {
header('Content-Type: ' . $contentType);
echo file_get_contents($assetFile);
} else {
http_response_code(404);
}
return;
}
$device = new DeviceDetectionOnPremise();
$builder = new PipelineBuilder(['suppressProcessExceptions' => true]);
$pipeline = $builder->add($device)->build();
$flowData = $pipeline->createFlowData();
try {
$flowData->evidence->setFromWebRequest();
$flowData->process();
$device = $flowData->device;
Utils::setResponseHeader($flowData);
$showContactUs = ExampleUtils::getDataFileTier($flowData->pipeline->getElement('device')) === 'Lite';
?>
<head>
<title>User-Agent Client Hints Example</title>
<link rel="stylesheet" href="/css/examples-main.min.css" />
</head>
<div class="c-eg-page">
<h2 class="c-eg-page__title">User-Agent Client Hints example</h2>
<p class="c-eg-page__lead">
By default, the user-agent, sec-ch-ua and sec-ch-ua-mobile HTTP headers are sent.
This means that on the first request, the server can determine the browser from
sec-ch-ua while other details must be derived from the user-agent.
</p>
<p class="c-eg-page__lead">
If the server determines that the browser supports client hints, then it may request
additional client hints headers by setting the Accept-CH header in the response.
Select the <strong>Make second request</strong> button below to send another request
to the server. This time, any additional client hints headers that have been requested
will be included.
</p>
<div class="c-eg-button-row">
<button type="button" class="b-btn" onclick="redirect()">Make second request</button>
</div>
<div id="evidence">
<h3 class="c-eg-page__heading">Evidence values used</h3>
<p class="c-eg-legend">
Evidence was
<span class="c-eg-legend__swatch c-eg-legend__swatch--used">used</span>
/
<span class="c-eg-legend__swatch c-eg-legend__swatch--present">present</span>
for detection
</p>
<table class="c-eg-table">
<thead class="c-eg-table__head">
<tr class="c-eg-table__row">
<th class="c-eg-table__cell">Key</th>
<th class="c-eg-table__cell">Value</th>
</tr>
</thead>
<tbody>
<?php
foreach ($flowData->evidence->getAll() as $key => $value) {
if ($flowData->pipeline->getElement('device')->getEvidenceKeyFilter()->filterEvidenceKey($key)) {
echo "<tr class='c-eg-table__row c-eg-table__row--used'>";
} else {
echo "<tr class='c-eg-table__row c-eg-table__row--present'>";
}
echo '<td class="c-eg-table__cell c-eg-table__cell--key">' . htmlspecialchars(strval($key)) . '</td>';
echo '<td class="c-eg-table__cell">' . htmlspecialchars(strval($value)) . '</td>';
echo '</tr>';
}
?>
</tbody>
</table>
</div>
<h3 class="c-eg-page__heading">Detection results</h3>
<p id="description" class="c-eg-page__lead"></p>
<table class="c-eg-table">
<thead class="c-eg-table__head">
<tr class="c-eg-table__row">
<th class="c-eg-table__cell">Key</th>
<th class="c-eg-table__cell">Value</th>
</tr>
</thead>
<tbody>
<tr class="c-eg-table__row c-eg-table__row--alt"><td class="c-eg-table__cell c-eg-table__cell--key">Hardware Vendor:</td><td class="c-eg-table__cell"><?php echo htmlspecialchars(ExampleUtils::getHumanReadable($device, 'hardwarevendor')); ?></td></tr>
<tr class="c-eg-table__row"><td class="c-eg-table__cell c-eg-table__cell--key">Hardware Name:</td><td class="c-eg-table__cell"><?php echo htmlspecialchars(ExampleUtils::getHumanReadable($device, 'hardwarename')); ?></td></tr>
<tr class="c-eg-table__row c-eg-table__row--alt"><td class="c-eg-table__cell c-eg-table__cell--key">Device Type:</td><td class="c-eg-table__cell"><?php echo htmlspecialchars(ExampleUtils::getHumanReadable($device, 'devicetype')); ?></td></tr>
<tr class="c-eg-table__row"><td class="c-eg-table__cell c-eg-table__cell--key">Platform Vendor:</td><td class="c-eg-table__cell"><?php echo htmlspecialchars(ExampleUtils::getHumanReadable($device, 'platformvendor')); ?></td></tr>
<tr class="c-eg-table__row c-eg-table__row--alt"><td class="c-eg-table__cell c-eg-table__cell--key">Platform Name:</td><td class="c-eg-table__cell"><?php echo htmlspecialchars(ExampleUtils::getHumanReadable($device, 'platformname')); ?></td></tr>
<tr class="c-eg-table__row"><td class="c-eg-table__cell c-eg-table__cell--key">Platform Version:</td><td class="c-eg-table__cell"><?php echo htmlspecialchars(ExampleUtils::getHumanReadable($device, 'platformversion')); ?></td></tr>
<tr class="c-eg-table__row c-eg-table__row--alt"><td class="c-eg-table__cell c-eg-table__cell--key">Browser Vendor:</td><td class="c-eg-table__cell"><?php echo htmlspecialchars(ExampleUtils::getHumanReadable($device, 'browservendor')); ?></td></tr>
<tr class="c-eg-table__row"><td class="c-eg-table__cell c-eg-table__cell--key">Browser Name:</td><td class="c-eg-table__cell"><?php echo htmlspecialchars(ExampleUtils::getHumanReadable($device, 'browsername')); ?></td></tr>
<tr class="c-eg-table__row c-eg-table__row--alt"><td class="c-eg-table__cell c-eg-table__cell--key">Browser Version:</td><td class="c-eg-table__cell"><?php echo htmlspecialchars(ExampleUtils::getHumanReadable($device, 'browserversion')); ?></td></tr>
</tbody>
</table>
<?php if ($showContactUs) { ?>
<div class="c-eg-message">
<p class="c-eg-message__text">The paid data file adds daily automatic updates, non-human identification and IP intelligence. <a href="/contact-us?utm_source=code&utm_medium=example&utm_campaign=51degrees-php&utm_content=examples-onpremise-useragentclienthints-web.php&utm_term=paid-data-file">Contact us</a> to explore the options.</p>
<a class="b-btn c-eg-message__cta" href="/contact-us?utm_source=code&utm_medium=example&utm_campaign=51degrees-php&utm_content=examples-onpremise-useragentclienthints-web.php&utm_term=paid-data-file">Contact us</a>
</div>
<?php } ?>
</div>
<script>
function redirect() {
sessionStorage.reloadAfterPageLoad = true;
window.location.reload(true);
}
window.onload = function () {
if (sessionStorage.reloadAfterPageLoad) {
document.getElementById('description').innerHTML = 'The information shown below is determined using <strong>User-Agent Client Hints</strong> that was sent in the request to obtain additional evidence. If no additional information appears then it may indicate an external problem such as <strong>User-Agent Client Hints</strong> being disabled in your browser.';
sessionStorage.reloadAfterPageLoad = false;
} else {
document.getElementById('description').innerHTML = 'The following values are determined by server-side device detection on the first request.';
}
};
</script>
<?php
} finally {
$flowData->close();
$pipeline->close();
}
Definition ExampleUtils.php:27