Use PHP functions in JavaScript

JavaScript version_compare

Compares two "PHP-standardized" version number strings

1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
2021
22
23
24
2526
27
28
29
3031
32
33
34
3536
37
38
39
4041
42
43
44
4546
47
48
49
5051
52
53
54
5556
57
58
59
6061
62
63
64
6566
67
68
69
7071
72
73
74
7576
77
78
79
8081
82
83
84
8586
87
88
89
9091
92
93
94
9596
97
98
99
100101
102
103
104
105106
107
108
109
110111
112
113
114
115116
117
function version_compare (v1, v2, operator) {
    // Compares two "PHP-standardized" version number strings  
    // 
    // version: 1109.2015
    // discuss at: http://phpjs.org/functions/version_compare    // +      original by: Philippe Jausions (http://pear.php.net/user/jausions)
    // +      original by: Aidan Lister (http://aidanlister.com/)
    // + reimplemented by: Kankrelune (http://www.webfaktory.info/)
    // +      improved by: Brett Zamir (http://brett-zamir.me)
    // +      improved by: Scott Baker    // +      improved by: Theriault
    // *        example 1: version_compare('8.2.5rc', '8.2.5a');
    // *        returns 1: 1
    // *        example 2: version_compare('8.2.50', '8.2.52', '<');
    // *        returns 2: true    // *        example 3: version_compare('5.3.0-dev', '5.3.0');
    // *        returns 3: -1
    // *        example 4: version_compare('4.1.0.52','4.01.0.51');
    // *        returns 4: 1
    // BEGIN REDUNDANT    this.php_js = this.php_js || {};
    this.php_js.ENV = this.php_js.ENV || {};
    // END REDUNDANT
    // Important: compare must be initialized at 0. 
    var i = 0,        x = 0,
        compare = 0,
        // vm maps textual PHP versions to negatives so they're less than 0.
        // PHP currently defines these as CASE-SENSITIVE. It is important to
        // leave these as negatives so that they can come before numerical versions        // and as if no letters were there to begin with.
        // (1alpha is < 1 and < 1.1 but > 1dev1)
        // If a non-numerical value can't be mapped to this table, it receives
        // -7 as its value.
        vm = {            'dev': -6,
            'alpha': -5,
            'a': -5,
            'beta': -4,
            'b': -4,            'RC': -3,
            'rc': -3,
            '#': -2,
            'p': -1,
            'pl': -1        },
        // This function will be called to prepare each version argument.
        // It replaces every _, -, and + with a dot.
        // It surrounds any nonsequence of numbers/dots with dots.
        // It replaces sequences of dots with a single dot.        //    version_compare('4..0', '4.0') == 0
        // Important: A string of 0 length needs to be converted into a value
        // even less than an unexisting value in vm (-7), hence [-8].
        // It's also important to not strip spaces because of this.
        //   version_compare('', ' ') == 1        prepVersion = function (v) {
            v = ('' + v).replace(/[_\-+]/g, '.');
            v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.');
            return (!v.length ? [-8] : v.split('.'));
        },        // This converts a version component to a number.
        // Empty component becomes 0.
        // Non-numerical component becomes a negative number.
        // Numerical component becomes itself as an integer.
        numVersion = function (v) {            return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10));
        };
    v1 = prepVersion(v1);
    v2 = prepVersion(v2);
    x = Math.max(v1.length, v2.length);    for (i = 0; i < x; i++) {
        if (v1[i] == v2[i]) {
            continue;
        }
        v1[i] = numVersion(v1[i]);        v2[i] = numVersion(v2[i]);
        if (v1[i] < v2[i]) {
            compare = -1;
            break;
        } else if (v1[i] > v2[i]) {            compare = 1;
            break;
        }
    }
    if (!operator) {        return compare;
    }
 
    // Important: operator is CASE-SENSITIVE.
    // "No operator" seems to be treated as "<."    // Any other values seem to make the function return null.
    switch (operator) {
    case '>':
    case 'gt':
        return (compare > 0);    case '>=':
    case 'ge':
        return (compare >= 0);
    case '<=':
    case 'le':        return (compare <= 0);
    case '==':
    case '=':
    case 'eq':
        return (compare === 0);    case '<>':
    case '!=':
    case 'ne':
        return (compare !== 0);
    case '':    case '<':
    case 'lt':
        return (compare < 0);
    default:
        return null;    }
}
external links: original PHP docs | raw js source

Examples

» Example 1

Running

1
version_compare('8.2.5rc', '8.2.5a');

Should return

1
1

» Example 2

Running

1
version_compare('8.2.50', '8.2.52', '<');

Should return

1
true

Dependencies

No dependencies, you can use this function standalone.

Open syntax issues

php.js uses JsLint to help us keep our code consistent and prevent some common bugs.

Eventually we want all code to pass or at least take into consideration most fixes suggested by JsLint, following this JsLint configuration we’ve decided on.


Authors

Thanks to the following developers, you get to have version_compare goodness in JavaScript.

Comments

Add Comment
Use:
[CODE]
your_stuff('here');
[/CODE]
for proper code formatting
By submitting code here you are allowing us to use it in php.js hence dual licensing it under the MIT and GPL licenses

Gravatar
العاب بوابة حواء
Apr 17th Permalink

q  This is a very informative article. I was looking for these things and here I found it. I am doing a project and this information is very useful me. Some things in here I have not thought about before

Gravatar
Thériault
30 May '10 Permalink

q  @Scott Baker: Thank you for finding this. I fixed this and went ahead and fixed a few other bugs I found in this function (you can never be too nit picky), including:
- An empty string is acceptable as a version number. (Currently throws an error.) An empty string should always be less-than a non-empty string (PHP behavior).
- Both the operators and the version words were being treated as case-insensitive when PHP treats them as case-sensitive.
- An invalid operator should make the function return null instead of using the "<" operator as a fallback.

The code has also been reduced by many lines and documented better. You can get the updated code here http://github.com/kvz/phpjs/raw/master/functions/info/version_compare.js before it is updated on the main website.

Gravatar
Scott Baker
28 May '10 Permalink

q  This may be nit picky, but I've seen version numbers with leading zeros as filler. This breaks this compare.

Correct:

version_compare('4.1.0.52','4.1.0.52') = 0



Not Correct:

version_compare('4.1.0.52','4.01.0.51') = 0
version_compare('4.1.0.52','4.01.0.51','>') = false


Contribute a New function

More functions

In this category

assert
assert_options
get_cfg_var
get_defined_constants
get_extension_funcs
get_include_path
get_included_files
get_required_files
getenv
getlastmod
ini_alter
ini_get
ini_get_all
ini_restore
ini_set
php_ini_loaded_file
php_ini_scanned_files
phpversion
putenv
restore_include_path
set_include_path
set_time_limit
» version_compare

Support us

spread the word:


Use any PHP function in JavaScript


These kind folks have already donated: AYHAN BARI*, Nikita Ekshiyan, Nikita Ekshiyan, Petr Pavel, @HalfWinter, Paulo Freitas, Andros Peña Romo, @andorosu, Raimund Szabo, Nitin Gupta, @nikosdion, Anonymous, Anonymous and Shawn Houser.
<your name here>

Click here to lend your support to: phpjs and make a donation at www.pledgie.com !