# PhpUserAgent parses three regular expressions and refuses to guess

> PhpUserAgent is a PHP user-agent string parser from donatj that stays under 200 lines and three regular expressions, and deliberately leaves OS versions and some platforms unparsed because the strings do not carry them. That refusal is the design, and it is the part to read before you adopt it.

**donatj/PhpUserAgent** — Lightning Fast, Minimalist PHP User Agent String Parser.

- Repository: https://github.com/donatj/PhpUserAgent
- Website: https://donatstudios.com/PHP-Parser-HTTP_USER_AGENT
- Stars: 598 · Forks: 127
- Language: PHP
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/donatj-phpuseragent

## Three regular expressions is the entire detection engine

PhpUserAgent is described as a simple, streamlined PHP user-agent parser, and the project's own pitch is about size. It states that the library is less than 200 lines of code and consists of just three regular expressions, that it detects all modern browsers in a very light, quick and understandable fashion, that it can correctly identify exotic versions of IE that others fail on, and that it offers 100 percent unit test coverage while being installable via Composer. The repository layout matches that description. The src/ directory holds the parser, tests/ holds the test suite and fixtures, composer.json defines the package, phpunit.xml.dist configures the test runner, and a Makefile provides the targets. There is a Makefile with a test target that runs ./vendor/bin/phpunit --coverage-text, so the coverage claim is something you can reproduce yourself rather than take on trust.

## The parser answers three questions and refuses the fourth

The public interface returns platform, browser and browser version, and the documentation is emphatic about what is not there. The README says this is not meant as a browser knowledge engine but rather a simple parser, and that anything the user agent string itself does not adequately carry will simply not be returned by the parser. Operating system version is the case that gets the longest explanation. User-agent strings are stated to be not a reliable source of OS version, because many agents simply do not send the information and others provide varying levels of accuracy, and because parsing Windows versions alone almost nearly doubles the size of the code. The author's stated preference is keeping the thing tiny and accurate rather than adding niche features. This is a real constraint rather than a missing feature, and it means the parser answers what platform family a request came from, not which specific Windows build or which iOS release.

## Three platforms are undetectable by design

Two limits are called out by name and one is a documented GitHub issue. Brave is not differentiable from Chrome, and the README attributes this to a design decision on Brave's part, so every Brave request arrives looking like Chrome. iPadOS 13 and later, hardened further in 14, returns the exact same user agent string as macOS, so an iPad is not distinguishable from a Mac, and the project links that to issue 69. The third case is conditional. There is a branch named os_version_detection created for a client that does attempt OS version detection, and the author updates it from time to time, but the accompanying advice is blunt: if you need to reliably detect OS version, using user-agent is not the way to do it, and the recommendation is to use JavaScript. So the parser has a place to look for what it deliberately does not do, and the project would rather you use a different signal entirely.

## Composer install and the procedural call

Installation is through Packagist via Composer, and the requirements are PHP 5.4.0 or newer plus the ctype extension.

```bash
composer require 'donatj/phpuseragentparser'
```

The classic procedural usage loads the Composer autoloader and calls the parse function, which takes the user agent string from the current request by default.

```php
<?php
require __DIR__ . '/../vendor/autoload.php';
$uaInfo = donatj\UserAgent\parse_user_agent();
echo $uaInfo[donatj\UserAgent\PLATFORM] . PHP_EOL;
echo $uaInfo[donatj\UserAgent\BROWSER] . PHP_EOL;
echo $uaInfo[donatj\UserAgent\BROWSER_VERSION] . PHP_EOL;
```

One migration detail catches people upgrading. The 1.x release does not break compatibility with 0.x and nothing needs to change to upgrade, but the global parse_user_agent function is now deprecated in favour of the namespaced \donatj\UserAgent\parse_user_agent, which functions exactly the same, and existing calls can be replaced directly. The 1.x line also adds a convenience object wrapper, which is the form most new code should use.

## The object wrapper is the form to build on

The object-oriented wrapper gives you a UserAgentParser instance, and it supports two calling styles.

```php
<?php
use donatj\UserAgent\UserAgentParser;
require __DIR__ . '/../vendor/autoload.php';
$parser = new UserAgentParser();
$ua = $parser->parse();
$ua = $parser();
echo $ua->platform() . PHP_EOL;
echo $ua->browser() . PHP_EOL;
echo $ua->browserVersion() . PHP_EOL;
```

The parse method and the invocation syntax on the instance do the same thing, so the difference is stylistic rather than behavioural. What changes is the access pattern: the procedural form reads array entries with the PLATFORM, BROWSER and BROWSER_VERSION constants, while the object form exposes platform(), browser() and browserVersion() as methods. If you are integrating into a codebase that prefers objects, this is the shape to target, and the examples directory in the repository holds both procedural.php and object-oriented.php so you can copy the form you prefer. The constants for platforms and browsers live in the donatj\UserAgent\Platforms and donatj\UserAgent\Browsers classes, and the platform list runs from Macintosh, Chrome OS, Linux, Windows and Android through FreeBSD, Fuchsia, the Nintendo and PlayStation families, Sailfish, Symbian, Tizen, Windows Phone and the Xbox consoles.

## Bots live in the browser list too, and that is acknowledged

The browser constants are where the project is candid about a bit of mess. Googlebot, bingbot, Baiduspider, AdsBot-Google, Applebot, facebookexternalhit, FeedValidator, curl and ChatGPT-User all sit in the browser list rather than in a separate class. The note explains why: before bots were given their own separate class, a number of them were added to the browser list, and they appear in both lists for backward compatibility, with the expectation that this is likely to be remedied in a future major release. The practical consequence for you is that a filter written as a browser check will also catch crawlers, and one written as a bot check may be too narrow if you expected every crawler to be listed there. The release history shows the list growing over time rather than being curated up front. Version 1.10.0 added Naver Whale support, version 1.11.0 added Fuchsia, and version 1.12.0 is titled Attack of the Bots, which is the release where the bot coverage expanded.

## The fixture file and the generator explain how the list grows

The Makefile at the top of the repository is the mechanism behind the constant lists and the test fixtures, and it is worth understanding before you add a browser yourself. There is a generate target that runs the user agent sorter script and writes a temporary JSON file that is moved over the test fixture, then runs the constant generator. There is an init target that does the same from the init script and then invokes generate. The clean target removes the working fixture and touches an empty one. The fixtures live in tests/, with user_agents.json as the working file and user_agents.dist.json as the distributed version, and the bin/ directory holds user_agent_sorter.php, constant_generator.php and init_user_agent.php. The practical upshot is that the browser and platform constants are generated from data, not hand written, so adding a browser means adding an entry to the fixture data and regenerating, and the sorter script exists to order that data. The repository also includes a .mddoc.xml for generating documentation and a .helpers/ directory.

## Conclusion

PhpUserAgent suits PHP applications that need a browser name, a browser version and a platform family, and that value a small auditable dependency over a large feature list. It does not suit anything that needs operating system versions, and it cannot distinguish Brave from Chrome or an iPad running iPadOS 13 from a Mac. Before adopting it, read the parser source under src/ and confirm three regular expressions are what you want to maintain, run composer require donatj/phpuseragentparser on PHP 5.4 or newer with ext-ctype, and decide separately how you will detect OS versions if your product depends on them.

## FAQ

### How do I install PhpUserAgent?

Install it through Composer with composer require 'donatj/phpuseragentparser'. The requirements are PHP 5.4.0 or newer and the ext-ctype extension.

### Does PhpUserAgent detect the operating system version?

No. The README states that user-agent strings are not a reliable source of OS version and that this parser does not provide it. There is an os_version_detection branch for anyone who wants to look, but the project recommends using JavaScript instead if you need reliable OS detection.

### Can PhpUserAgent tell Brave apart from Chrome?

No. The README states that Brave is not differentiable from Chrome, which it attributes to a design decision on Brave's part. iPadOS 13 and later is likewise indistinguishable from macOS by user agent string.

### What is the difference between the global parse_user_agent and the namespaced one?

They behave identically. The global parse_user_agent is deprecated in the 1.x line and was replaced by \donatj\UserAgent\parse_user_agent, and existing calls can be swapped without other changes.

### How do I run the PhpUserAgent tests?

The repository Makefile has a test target that runs ./vendor/bin/phpunit --coverage-text, so make test runs the suite with a coverage summary.

## Sources

- [donatj/PhpUserAgent on GitHub](https://github.com/donatj/PhpUserAgent)
- [License: MIT](https://github.com/donatj/PhpUserAgent/blob/master/LICENSE)
- [Project website](https://donatstudios.com/PHP-Parser-HTTP_USER_AGENT)
- [README](https://github.com/donatj/PhpUserAgent/blob/master/README.md)
- [Releases](https://github.com/donatj/PhpUserAgent/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/donatj-phpuseragent
