cbschuld / Browser.php

A PHP Class to detect a user's Browser. This encapsulation provides a breakdown of the browser and the version of the browser using the browser's user-agent string. This is not a guaranteed solution but provides an overall accurate way to detect what browser a user is using.
https://chrisschuld.com/projects/browser-php-detecting-a-users-browser-from-php/
MIT License
580 stars 303 forks source link

Retrieved version number and PHP 8 #94

Open chrisgraham opened 4 years ago

chrisgraham commented 4 years ago

The getVersion method is documented to return only a single period:

    /**
     * The version of the browser.
     * @return string Version of the browser (will only contain alpha-numeric characters and a period)
     */
    public function getVersion()
    {
        return $this->_version;
    }

However, it may contain multiple. E.g. '15.1.4'.

This was not really an obvious issue, until PHP 8, which changes how automatic casting works...

php -r 'var_dump("15.1.4" == 15.1);' bool(false)

It returns false as it now does a string comparison rather than an automatic cast, if it doesn't fully match the pattern of a float (I think!!). I was relying on this, as I'm sure other users were.

This change to the setVersion method fixes it by making it only have one period section:

    /**
     * Set the version of the browser
     * @param string $version The version of the Browser
     */
    public function setVersion($version)
    {
        $this->_version = preg_replace('#^([^\.]*\.[^\.]*)\..*#', '$1', preg_replace('/[^0-9,.,a-z,A-Z-]/', '', $version));
    }

This provides us a return value that continues to work...

$ php -r 'var_dump("15.1" == 15.1);'
bool(true)
cbschuld commented 4 years ago

@chrisgraham definitely an issue - I hear you. For an acceptable stopgap in PHP8 you could cast to a double; I'd really like to not change the setter/getter scenario of the version if we can (just due to usage)

php -r 'var_dump((double)"15.1.4" == (double)15.1);'

Here is an execution from 7.3.11:

php -r 'var_dump((double)"15.1.4" == (double)15.1);'
bool(true)

and one from 8.0.0 CR2

PHP 8.0.0RC2 (cli) (built: Oct 22 2020 06:35:43) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.0-dev, Copyright (c) Zend Technologies
/ # php -r 'var_dump((double)"15.1.4" == (double)15.1);'
bool(true)
chrisgraham commented 4 years ago

That's fine, thanks for the reply. If you don't want to go my way for now, I suggest just securing the way you're doing it. Fix "will only contain alpha-numeric characters and a period" to "will only contain alpha-numeric characters and periods, e.g. 15.1.4", and actually I'd advise people to use PHP's version_compare function.