Skip to content

Commit 2b7eb0e

Browse files
committed
Disallow version_compare() $operator abbreviations
`version_compare()` does a sloppy check for the `$operators` argument which allows arbitrary abbreviations of the supported operators to be accepted. This is both undocumented and unexpected, and could lead to subtle BC breaks, if the order of the comparisions will be changed. Therefore we change to strict comparisons. Closes GH-6510.
1 parent 269a884 commit 2b7eb0e

File tree

3 files changed

+34
-9
lines changed

3 files changed

+34
-9
lines changed

UPGRADING

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ PHP 8.1 UPGRADE NOTES
1919
1. Backward Incompatible Changes
2020
========================================
2121

22+
- Standard:
23+
. version_compare() no longer accepts undocumented operator abbreviations.
24+
2225
========================================
2326
2. New Features
2427
========================================
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--TEST--
2+
version_compare() no longer supports operator abbreviations
3+
--FILE--
4+
<?php
5+
$abbrevs = ['', 'l', 'g', 'e', '!', 'n'];
6+
foreach ($abbrevs as $op) {
7+
try {
8+
version_compare('1', '2', $op);
9+
echo "'$op' succeeded\n";
10+
} catch (ValueError $err) {
11+
echo "'$op' failed\n";
12+
}
13+
}
14+
?>
15+
--EXPECT--
16+
'' failed
17+
'l' failed
18+
'g' failed
19+
'e' failed
20+
'!' failed
21+
'n' failed

ext/standard/versioning.c

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -203,37 +203,38 @@ php_version_compare(const char *orig_ver1, const char *orig_ver2)
203203

204204
PHP_FUNCTION(version_compare)
205205
{
206-
char *v1, *v2, *op = NULL;
207-
size_t v1_len, v2_len, op_len = 0;
206+
char *v1, *v2;
207+
zend_string *op = NULL;
208+
size_t v1_len, v2_len;
208209
int compare;
209210

210211
ZEND_PARSE_PARAMETERS_START(2, 3)
211212
Z_PARAM_STRING(v1, v1_len)
212213
Z_PARAM_STRING(v2, v2_len)
213214
Z_PARAM_OPTIONAL
214-
Z_PARAM_STRING_OR_NULL(op, op_len)
215+
Z_PARAM_STR_OR_NULL(op)
215216
ZEND_PARSE_PARAMETERS_END();
216217

217218
compare = php_version_compare(v1, v2);
218219
if (!op) {
219220
RETURN_LONG(compare);
220221
}
221-
if (!strncmp(op, "<", op_len) || !strncmp(op, "lt", op_len)) {
222+
if (zend_string_equals_literal(op, "<") || zend_string_equals_literal(op, "lt")) {
222223
RETURN_BOOL(compare == -1);
223224
}
224-
if (!strncmp(op, "<=", op_len) || !strncmp(op, "le", op_len)) {
225+
if (zend_string_equals_literal(op, "<=") || zend_string_equals_literal(op, "le")) {
225226
RETURN_BOOL(compare != 1);
226227
}
227-
if (!strncmp(op, ">", op_len) || !strncmp(op, "gt", op_len)) {
228+
if (zend_string_equals_literal(op, ">") || zend_string_equals_literal(op, "gt")) {
228229
RETURN_BOOL(compare == 1);
229230
}
230-
if (!strncmp(op, ">=", op_len) || !strncmp(op, "ge", op_len)) {
231+
if (zend_string_equals_literal(op, ">=") || zend_string_equals_literal(op, "ge")) {
231232
RETURN_BOOL(compare != -1);
232233
}
233-
if (!strncmp(op, "==", op_len) || !strncmp(op, "=", op_len) || !strncmp(op, "eq", op_len)) {
234+
if (zend_string_equals_literal(op, "==") || zend_string_equals_literal(op, "=") || zend_string_equals_literal(op, "eq")) {
234235
RETURN_BOOL(compare == 0);
235236
}
236-
if (!strncmp(op, "!=", op_len) || !strncmp(op, "<>", op_len) || !strncmp(op, "ne", op_len)) {
237+
if (zend_string_equals_literal(op, "!=") || zend_string_equals_literal(op, "<>") || zend_string_equals_literal(op, "ne")) {
237238
RETURN_BOOL(compare != 0);
238239
}
239240

0 commit comments

Comments
 (0)