(PHP 4 >= 4.1.0, PHP 5, PHP 7, PHP 8)
version_compare — Compares two "PHP-standardized" version number strings
version_compare() compares two "PHP-standardized" version number strings.
The function first replaces _
, -
and
+
with a dot .
in the version
strings and also inserts dots .
before and after any
non number so that for example '4.3.2RC1' becomes '4.3.2.RC.1'. Then it
compares the parts starting from left to right. If a part contains
special version strings these are handled in the following order:
any string not found in this list
<
dev
< alpha
=
a
< beta
=
b
< RC
=
rc
< #
<
pl
= p
. This way not only versions
with different levels like '4.1' and '4.1.2' can be compared but also any
PHP specific version containing development state.
version1
First version number.
version2
Second version number.
operator
An optional operator. The possible operators
are: <
, lt
,
<=
, le
, >
,
gt
, >=
, ge
,
==
, =
, eq
,
!=
, <>
, ne
respectively.
This parameter is case-sensitive, values should be lowercase.
By default, version_compare() returns
-1
if the first version is lower than the second,
0
if they are equal, and
1
if the second is lower.
When using the optional operator
argument, the
function will return true
if the relationship is the one specified
by the operator, false
otherwise.
The examples below use the PHP_VERSION
constant,
because it contains the value of the PHP version that is executing
the code.
Example #1 version_compare() examples
<?php
if (version_compare(PHP_VERSION, '7.0.0') >= 0) {
echo 'I am at least PHP version 7.0.0, my version: ' . PHP_VERSION . "\n";
}
if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
echo 'I am at least PHP version 5.3.0, my version: ' . PHP_VERSION . "\n";
}
if (version_compare(PHP_VERSION, '5.0.0', '>=')) {
echo 'I am at least PHP version 5.0.0, my version: ' . PHP_VERSION . "\n";
}
if (version_compare(PHP_VERSION, '5.0.0', '<')) {
echo 'I am still PHP 4, my version: ' . PHP_VERSION . "\n";
}
?>
Note:
The
PHP_VERSION
constant holds current PHP version.
Note:
Note that pre-release versions, such as 5.3.0-dev, are considered lower than their final release counterparts (like 5.3.0).
Note:
Special version strings such as
alpha
andbeta
are case sensitive. Version strings from arbitrary sources that do not adhere to the PHP standard may need to be lowercased via strtolower() before calling version_compare().
[editors note]
snipbit fixed after comment from Matt Mullenweg
--jm
[/editors note]
so in a nutshell... I believe it works best like this:
<?php
if (version_compare(phpversion(), "4.3.0", ">=")) {
// you're on 4.3.0 or later
} else {
// you're not
}
?>
This little script can perhaps help you understand version comparison a little better - the output is displayed in the comment at the top. Tweak the list of versions if you need more examples...
<?php
# 1 lt 1.0
# 1.0 lt 1.01
# 1.01 eq 1.1
# 1.1 lt 1.10
# 1.10 gt 1.10b
# 1.10b lt 1.10.0
header('Content-type: text/plain');
$versions = array(
'1',
'1.0',
'1.01',
'1.1',
'1.10',
'1.10b',
'1.10.0',
);
$comps = array(
-1 => 'lt',
0 => 'eq',
1 => 'gt'
);
foreach ($versions as $version) {
if (isset($last)) {
$comp = version_compare($last, $version);
echo str_pad($last,8,' ',STR_PAD_LEFT) . " {$comps[$comp]}{$version}\n";
}
$last = $version;
}
?>
Since this function considers 1 < 1.0 < 1.0.0, others might find this function useful (which considers 1 == 1.0):
<?php
//Compare two sets of versions, where major/minor/etc. releases are separated by dots.
//Returns 0 if both are equal, 1 if A > B, and -1 if B < A.
function version_compare2($a, $b)
{
$a = explode(".", rtrim($a, ".0")); //Split version into pieces and remove trailing .0
$b = explode(".", rtrim($b, ".0")); //Split version into pieces and remove trailing .0
foreach ($a as $depth => $aVal)
{ //Iterate over each piece of A
if (isset($b[$depth]))
{ //If B matches A to this depth, compare the values
if ($aVal > $b[$depth]) return 1; //Return A > B
else if ($aVal < $b[$depth]) return -1; //Return B > A
//An equal result is inconclusive at this point
}
else
{ //If B does not match A to this depth, then A comes after B in sort order
return 1; //so return A > B
}
}
//At this point, we know that to the depth that A and B extend to, they are equivalent.
//Either the loop ended because A is shorter than B, or both are equal.
return (count($a) < count($b)) ? -1 : 0;
}
?>
Please note that supplying an operator that is not listed (e.g. ===), this function returns NULL instead of false.
Tested on PHP5.3.0, Win32
Note that both leading and trailing spaces on your version numbers can break version_compare().
Tested on PHP 5.6.8:
<?php
echo "\nShould be 0";
echo "\n '1.0.0-pl' vs. '1.0.0-pl' ---> " . version_compare('1.0.0-pl', '1.0.0-pl');
echo "\n '1.0.0-pl' vs. ' 1.0.0-pl' ---> " . version_compare('1.0.0-pl', ' 1.0.0-pl');
echo "\n ' 1.0.0-pl' vs. '1.0.0-pl' ---> " . version_compare(' 1.0.0-pl', '1.0.0-pl');
echo "\n '1.0.0-pl' vs. '1.0.0-pl ' ---> " . version_compare('1.0.0-pl', '1.0.0-pl ');
echo "\n '1.0.0-pl ' vs. '1.0.0-pl' ---> " . version_compare('1.0.0-pl ', '1.0.0-pl');
echo "\n\nShould be 1";
echo "\n '1.1.1-pl' vs. '1.0.0-pl' ---> " . version_compare('1.1.1-pl', '1.0.0-pl');
echo "\n ' 1.1.1-pl' vs. '1.0.0-pl' ---> " . version_compare(' 1.1.1-pl', '1.0.0-pl');
echo "\n\nShould be -1";
echo "\n '1.0.0-pl' vs. '1.1.1-pl' ---> " . version_compare('1.0.0-pl', '1.1.1-pl');
echo "\n '1.0.0-pl' vs. ' 1.1.1-pl' ---> " . version_compare('1.0.0-pl', ' 1.1.1-pl');
/* Output
Should be 0
'1.0.0-pl' vs. '1.0.0-pl' ---> 0
'1.0.0-pl' vs. ' 1.0.0-pl' ---> 1
' 1.0.0-pl' vs. '1.0.0-pl' ---> -1
'1.0.0-pl' vs. '1.0.0-pl ' ---> 1
'1.0.0-pl ' vs. '1.0.0-pl' ---> -1
Should be 1
'1.1.1-pl' vs. '1.0.0-pl' ---> 1
' 1.1.1-pl' vs. '1.0.0-pl' ---> -1
Should be -1
'1.0.0-pl' vs. '1.1.1-pl' ---> -1
'1.0.0-pl' vs. ' 1.1.1-pl' ---> 1
*/
Something that may trip some folks up, but is useful to mention is that the following version comparison does not work quite as I expected:
version_compare('1.0.1', '1.0pl1', '>')
However, its quite easy to get working:
version_compare('1.0.1', '1.0.0pl1', '>')
In case you need to handle more complex version numbers like alpha, beta,..., here is a little something that can help:
function multiExplode($delimiters,$string){
$pattern = '/['.preg_quote($delimiters).']/';
return(preg_split( $pattern, $string ));
}
function isInteger($input){
return(ctype_digit(strval($input)));
}
function keepIntsStartArray($arr){
$nonIntMappings=[
"alpha"=>1,
"beta"=>2,
"gamma"=>3,
"delta"=>4,
"epsilon"=>5,
"zeta"=>6,
"eta"=>7,
"theta"=>8,
"iota"=>9,
"kappa"=>10,
"lambda"=>11,
"mu"=>12,
"nu"=>13,
"xi"=>14,
"omicron"=>15,
"pi"=>16,
"rho"=>17,
"sigma"=>18,
"tau"=>19,
"upsilon"=>20,
"phi"=>21,
"chi"=>22,
"psi"=>23,
"omega"=>24,
];
$ret=[];
foreach($arr as $i){
if(!isInteger($i)){
if(!array_key_exists($i,$nonIntMappings)){
break;
}
$ret[]=$nonIntMappings[$i];
}
$ret[]=$i;
}
return($ret);
}
function appVersionBigger($v1,$v2,$orEqual=false){
$delimiters=".-+";
$a1=keepIntsStartArray(multiExplode($delimiters,$v1));
$a2=keepIntsStartArray(multiExplode($delimiters,$v2));
$len=count($a1);
if($len>count($a2)){
$len=count($a2);
}
for($i=0;$i<$len;$i++){
$n1=$a1[$i];
$n2=$a2[$i];
if($n1>$n2){
return(true);
}
if($n1<$n2){
return(false);
}
}
if(count($a1)>count($a2)){
return(true);
}
if(count($a1)<count($a2)){
return(false);
}
return($orEqual);
}
// usage examples:
$versions=[
"1.2.3-45"=>"1.2.3-45",
"1.2.3-44"=>"1.2.3-45",
"1.2.3-46"=>"1.2.3-45",
"1.2.3"=>"1.2.3-45",
"1.2.4"=>"1.2.3-45",
"1.2.2"=>"1.2.3-45",
"1.2"=>"1.2.3-45",
"1.3"=>"1.2.3-45",
"1.2.3-ios"=>"1.2.3-and",
"1.2-ios"=>"1.2.3-and",
"2-ios"=>"1.2.3-and",
"1.2.3-alpha"=>"1.2.3-beta",
"1.2.3-beta"=>"1.2.3-alpha",
"1-gamma"=>"1.2.3-beta",
"1-alpha"=>"1.2.3-beta",
];
foreach($versions as $v1=>$v2){
echo("v1: ".$v1."\tv2: ".$v2."\tgt: ".(appVersionBigger($v1,$v2,false)?"true":"false")."\tge: ".(appVersionBigger($v1,$v2,true)?"true":"false")."\n");
}
// output with php version 8.1.8:
/*
v1: 1.2.3-45 v2: 1.2.3-45 gt: false ge: true
v1: 1.2.3-44 v2: 1.2.3-45 gt: false ge: false
v1: 1.2.3-46 v2: 1.2.3-45 gt: true ge: true
v1: 1.2.3 v2: 1.2.3-45 gt: false ge: false
v1: 1.2.4 v2: 1.2.3-45 gt: true ge: true
v1: 1.2.2 v2: 1.2.3-45 gt: false ge: false
v1: 1.2 v2: 1.2.3-45 gt: false ge: false
v1: 1.3 v2: 1.2.3-45 gt: true ge: true
v1: 1.2.3-ios v2: 1.2.3-and gt: false ge: true
v1: 1.2-ios v2: 1.2.3-and gt: false ge: false
v1: 2-ios v2: 1.2.3-and gt: true ge: true
v1: 1.2.3-alpha v2: 1.2.3-beta gt: false ge: false
v1: 1.2.3-beta v2: 1.2.3-alpha gt: true ge: true
v1: 1-gamma v2: 1.2.3-beta gt: true ge: true
v1: 1-alpha v2: 1.2.3-beta gt: false ge: false
*/
While `+` is typically used to append metadata that are not supposed to be accounted for version comparison, the PHP version_compare function will actually consider that it decreases the version (by less than the least significant number) so:
```
version_compare('1.0.0+something', '1.0.0', '>=')
```
will return `false`
If you're careful, this function actualy works quite nicely for comparing version numbers from programs other than PHP itself. I've used it to compare MySQL version numbers. The only issue is that version_compare doesn't recognize the 'gamma' addition that mysql uses as being later than 'alpha' or 'beta', because the latter two are treated specially. If you keep this in mind though, you should have no problems.
Actually, it works to any degree:
<?php
version_compare('1.2.3.4RC7.7', '1.2.3.4RC7.8')
version_compare('8.2.50.4', '8.2.52.6')
?>
will both give -1 (ie the left is lower than the right).