Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,9 @@ PDO_SQLITE:

RFC: https://wiki.php.net/rfc/new_rounding_modes_to_round_function
. debug_zval_dump() now indicates whether an array is packed.
. intval() now supports explicit octal integer prefixes ("0o"/"0O") in strings
when the base is 8 or 0.
This is a follow-up to https://wiki.php.net/rfc/explicit_octal_notation

========================================
6. New Functions
Expand Down
118 changes: 0 additions & 118 deletions ext/standard/tests/general_functions/intval_binary_prefix.phpt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
--TEST--
Test intval() function with integer strings with prefixes
--FILE--
<?php

$signs = [
'',
'+',
'-',
];

$whitespaces = [
'',
" \t\n\r\f\v",
];

$bases = [
2 => [
[
'0b',
'0B',
],
[
'1111111111111111111111111111111' => 0b1111111111111111111111111111111,
str_repeat('1', 65) => PHP_INT_MAX,
'1' => 1,
'000' => 0,
'001' => 1,
'00100' => 0b100,
],
],
8 => [
[
'0o',
'0O',
],
[
'7777777' => 0o7777777,
str_repeat('7', 22) => PHP_INT_MAX,
'7' => 0o7,
'000' => 0,
'007' => 0o7,
'00700' => 0o700,
],
],
16 => [
[
'0x',
'0X',
],
[
'FFFFFFF' => 0xFFFFFFF,
str_repeat('F', 18) => PHP_INT_MAX,
'A' => 0xA,
'000' => 0,
'00A' => 0xA,
'00A00' => 0xA00,
],
],
];

$i = 0;
echo "Checking well formed values:\n";
foreach ($bases as $base => [$prefixes, $values]) {
foreach ($values as $v => $expected_result) {
foreach ($signs as $sign) {
if ($sign == '-') {
if ($expected_result == PHP_INT_MAX) {
$expected_result = PHP_INT_MIN;
} else {
$expected_result *= -1;
}
}
foreach ($whitespaces as $whitespace_prefix) {
foreach ($whitespaces as $whitespace_suffix) {
foreach ($prefixes as $prefix) {
++$i;
$s = $whitespace_prefix . $sign . $prefix . $v . $whitespace_suffix;
$base0 = intval($s, 0);
$baseGiven = intval($s, $base);
if ($base0 != $baseGiven) {
echo "Base 0 and $base don't agree for:\n$s\n";
continue;
}
if ($base0 != $expected_result) {
echo "Base 0 is not the expected result for:\n$s\nExpected:\n$expected_result\nReality:\n$base0\n";
continue;
}
/* Check that with prefix the default behaviour is 0 */
if ($prefix != '') {
$baseDefault = intval($s);
if ($baseDefault != 0) {
echo "Base default is not 0:\n$s\n";
continue;
}
}
}
}
}
}
}
}

echo $i, ' values checked', "\n";

$badInputs = [
'0b',
'0B',
'b101',
'0b00200',
'--0b123',
'++0b123',
'0bb123',
'0 b123',
'0b1 1',
];

print "--- Bad Inputs - Base = 0 ---\n";
foreach ($badInputs as $input) {
var_dump(
intval($input, 0)
);
}

print '--- Done ---';

?>
--EXPECT--
Checking well formed values:
432 values checked
--- Bad Inputs - Base = 0 ---
int(0)
int(0)
int(0)
int(0)
int(0)
int(0)
int(0)
int(0)
int(1)
--- Done ---
52 changes: 35 additions & 17 deletions ext/standard/type.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,7 @@ PHP_FUNCTION(intval)
return;
}


if (base == 0 || base == 2) {
if (base == 0 || base == 2 || base == 8 || base == 16 ) {
char *strval = Z_STRVAL_P(num);
size_t strlen = Z_STRLEN_P(num);

Expand All @@ -173,27 +172,46 @@ PHP_FUNCTION(intval)
offset = 1;
}

if (strval[offset] == '0' && (strval[offset + 1] == 'b' || strval[offset + 1] == 'B')) {
char *tmpval;
strlen -= 2; /* Removing "0b" */
tmpval = emalloc(strlen + 1);

/* Place the unary symbol at pos 0 if there was one */
if (offset) {
tmpval[0] = strval[0];
}
if (strval[offset] != '0') {
goto basic_strtol;
}
switch (strval[offset + 1]) {
case 'b':
case 'B':
base = 2;
break;
case 'o':
case 'O':
base = 8;
break;
case 'x':
case 'X':
base = 16;
break;
default:
goto basic_strtol;
}

/* Copy the data from after "0b" to the end of the buffer */
memcpy(tmpval + offset, strval + offset + 2, strlen - offset);
tmpval[strlen] = 0;
char *tmpval;
strlen -= 2; /* Removing "0b"/"0x"/"0o" */
tmpval = emalloc(strlen + 1);

RETVAL_LONG(ZEND_STRTOL(tmpval, NULL, 2));
efree(tmpval);
return;
/* Place the unary symbol at pos 0 if there was one */
if (offset) {
tmpval[0] = strval[0];
}

/* Copy the data from after "0b" to the end of the buffer */
memcpy(tmpval + offset, strval + offset + 2, strlen - offset);
tmpval[strlen] = 0;

RETVAL_LONG(ZEND_STRTOL(tmpval, NULL, base));
efree(tmpval);
return;
}
}

basic_strtol:
RETVAL_LONG(ZEND_STRTOL(Z_STRVAL_P(num), NULL, base));
}
/* }}} */
Expand Down