--FILE--
<?php
$x = "bug";
-var_dump(isset($x[-1]));
+var_dump(isset($x[-10]));
var_dump(isset($x["1"]));
echo $x["1"]."\n";
?>
$simpleString = "Bogus String Text";
echo isset($simpleString->wrong)?"bug\n":"ok\n";
echo isset($simpleString["wrong"])?"bug\n":"ok\n";
-echo isset($simpleString[-1])?"bug\n":"ok\n";
+echo isset($simpleString[-20])?"bug\n":"ok\n";
echo isset($simpleString[0])?"ok\n":"bug\n";
echo isset($simpleString["0"])?"ok\n":"bug\n";
echo isset($simpleString["16"])?"ok\n":"bug\n";
$str = "test0123";
var_dump(empty($str[-1]));
+var_dump(empty($str[-10]));
+var_dump(empty($str[-4])); // 0
var_dump(empty($str[0]));
var_dump(empty($str[1]));
var_dump(empty($str[4])); // 0
// non-numeric offsets
print "- string ---\n";
var_dump(empty($str['-1']));
+var_dump(empty($str['-10']));
+var_dump(empty($str['-4'])); // 0
var_dump(empty($str['0']));
var_dump(empty($str['1']));
var_dump(empty($str['4'])); // 0
var_dump(empty($str[null]));
print "- double ---\n";
var_dump(empty($str[-1.1]));
+var_dump(empty($str[-10.5]));
+var_dump(empty($str[-4.1]));
var_dump(empty($str[-0.8]));
var_dump(empty($str[-0.1]));
var_dump(empty($str[0.2]));
?>
--EXPECTF--
- empty ---
+bool(false)
+bool(true)
bool(true)
bool(false)
bool(false)
bool(true)
bool(true)
- string ---
+bool(false)
+bool(true)
bool(true)
bool(false)
bool(false)
- null ---
bool(false)
- double ---
+bool(false)
+bool(true)
bool(true)
bool(false)
bool(false)
$str = "test0123";
var_dump(isset($str[-1]));
+var_dump(isset($str[-10]));
var_dump(isset($str[0]));
var_dump(isset($str[1]));
var_dump(isset($str[4])); // 0
// non-numeric offsets
print "- string ---\n";
var_dump(isset($str['-1']));
+var_dump(isset($str['-10']));
var_dump(isset($str['0']));
var_dump(isset($str['1']));
var_dump(isset($str['4'])); // 0
var_dump(isset($str[null]));
print "- double ---\n";
var_dump(isset($str[-1.1]));
+var_dump(isset($str[-10.5]));
var_dump(isset($str[-0.8]));
var_dump(isset($str[-0.1]));
var_dump(isset($str[0.2]));
?>
--EXPECTF--
- isset ---
+bool(true)
bool(false)
bool(true)
bool(true)
bool(false)
bool(false)
- string ---
+bool(true)
bool(false)
bool(true)
bool(true)
- null ---
bool(true)
- double ---
+bool(true)
bool(false)
bool(true)
bool(true)
---TEST--\r
-string offset 001\r
---FILE--\r
-<?php\r
-function foo($x) {\r
- var_dump($x);\r
-}\r
-\r
-$str = "abc";\r
-var_dump($str[-1]);\r
-var_dump($str[0]);\r
-var_dump($str[1]);\r
-var_dump($str[2]);\r
-var_dump($str[3]);\r
-var_dump($str[1][0]);\r
-var_dump($str[2][1]);\r
-\r
-foo($str[-1]);\r
-foo($str[0]);\r
-foo($str[1]);\r
-foo($str[2]);\r
-foo($str[3]);\r
-foo($str[1][0]);\r
-foo($str[2][1]);\r
-?>\r
---EXPECTF--\r
-Notice: Uninitialized string offset: -1 in %sstr_offset_001.php on line %d\r
-string(0) ""\r
-string(1) "a"\r
-string(1) "b"\r
-string(1) "c"\r
-\r
-Notice: Uninitialized string offset: 3 in %sstr_offset_001.php on line %d\r
-string(0) ""\r
-string(1) "b"\r
-\r
-Notice: Uninitialized string offset: 1 in %sstr_offset_001.php on line %d\r
-string(0) ""\r
-\r
-Notice: Uninitialized string offset: -1 in %sstr_offset_001.php on line %d\r
-string(0) ""\r
-string(1) "a"\r
-string(1) "b"\r
-string(1) "c"\r
-\r
-Notice: Uninitialized string offset: 3 in %sstr_offset_001.php on line %d\r
-string(0) ""\r
-string(1) "b"\r
-\r
-Notice: Uninitialized string offset: 1 in %sstr_offset_001.php on line %d\r
-string(0) ""\r
+--TEST--
+string offset 001
+--FILE--
+<?php
+// Test positive or null string offsets
+
+function foo($x) {
+ var_dump($x);
+}
+
+$str = "abc";
+var_dump($str[0]);
+var_dump($str[1]);
+var_dump($str[2]);
+var_dump($str[3]);
+var_dump($str[1][0]);
+var_dump($str[2][1]);
+
+foo($str[0]);
+foo($str[1]);
+foo($str[2]);
+foo($str[3]);
+foo($str[1][0]);
+foo($str[2][1]);
+?>
+--EXPECTF--
+string(1) "a"
+string(1) "b"
+string(1) "c"
+
+Notice: Uninitialized string offset: 3 in %sstr_offset_001.php on line %d
+string(0) ""
+string(1) "b"
+
+Notice: Uninitialized string offset: 1 in %sstr_offset_001.php on line %d
+string(0) ""
+string(1) "a"
+string(1) "b"
+string(1) "c"
+
+Notice: Uninitialized string offset: 3 in %sstr_offset_001.php on line %d
+string(0) ""
+string(1) "b"
+
+Notice: Uninitialized string offset: 1 in %sstr_offset_001.php on line %d
+string(0) ""
--- /dev/null
+--TEST--
+string offset 003
+--FILE--
+<?php
+// Test negative string offsets
+
+function foo($x) {
+ var_dump($x);
+}
+
+$str = "abcdef";
+var_dump($str[-10]);
+var_dump($str[-3]);
+var_dump($str[2][-2]);
+var_dump($str[2][-1]);
+
+foo($str[-10]);
+foo($str[-3]);
+foo($str[2][-2]);
+foo($str[2][-1]);
+?>
+--EXPECTF--
+Notice: Uninitialized string offset: -10 in %sstr_offset_003.php on line %d
+string(0) ""
+string(1) "d"
+
+Notice: Uninitialized string offset: -2 in %sstr_offset_003.php on line %d
+string(0) ""
+string(1) "c"
+
+Notice: Uninitialized string offset: -10 in %sstr_offset_003.php on line %d
+string(0) ""
+string(1) "d"
+
+Notice: Uninitialized string offset: -2 in %sstr_offset_003.php on line %d
+string(0) ""
+string(1) "c"
--- /dev/null
+--TEST--
+string offset 004
+--FILE--
+<?php
+// Test assignments using (positive and negative) string offsets
+
+$str = "abcdefghijklmno";
+$i = 3;
+$j = -4;
+
+$str{2} = 'C';
+var_dump($str);
+
+$str{$i} = 'Z';
+var_dump($str);
+
+$str{-5} = 'P';
+var_dump($str);
+
+$str{$j} = 'Q';
+var_dump($str);
+
+$str{-20} = 'Y';
+var_dump($str);
+
+$str{-strlen($str)} = strtoupper($str{0}); /* An exotic ucfirst() ;) */
+var_dump($str);
+
+$str{20} = 'N';
+var_dump($str);
+
+$str{-2} = 'UFO';
+var_dump($str);
+
+$str{-$i} = $str{$j*2};
+var_dump($str);
+?>
+--EXPECTF--
+string(15) "abCdefghijklmno"
+string(15) "abCZefghijklmno"
+string(15) "abCZefghijPlmno"
+string(15) "abCZefghijPQmno"
+
+Warning: Illegal string offset: -20 in %sstr_offset_004.php on line %d
+string(15) "abCZefghijPQmno"
+string(15) "AbCZefghijPQmno"
+string(21) "AbCZefghijPQmno N"
+string(21) "AbCZefghijPQmno UN"
+string(21) "AbCZefghijPQmno nUN"
zend_uchar c;
size_t string_len;
- if (offset < 0) {
+ if (offset < (zend_long)(-Z_STRLEN_P(str))) {
/* Error on negative offset */
zend_error(E_WARNING, "Illegal string offset: " ZEND_LONG_FMT, offset);
zend_string_release(Z_STR_P(str));
return;
}
+ if (offset < 0) { /* Handle negative offset */
+ offset += (zend_long)Z_STRLEN_P(str);
+ }
+
old_str = Z_STR_P(str);
if ((size_t)offset >= Z_STRLEN_P(str)) {
/* Extend string if needed */
offset = Z_LVAL_P(dim);
}
- if (UNEXPECTED(offset < 0) || UNEXPECTED(Z_STRLEN_P(container) <= (size_t)offset)) {
+ if (UNEXPECTED(Z_STRLEN_P(container) < (size_t)((offset < 0) ? -offset : (offset + 1)))) {
if (type != BP_VAR_IS) {
zend_error(E_NOTICE, "Uninitialized string offset: %pd", offset);
ZVAL_EMPTY_STRING(result);
ZVAL_NULL(result);
}
} else {
- zend_uchar c = (zend_uchar)Z_STRVAL_P(container)[offset];
+ zend_uchar c;
+ zend_long real_offset;
+
+ real_offset = (UNEXPECTED(offset < 0)) /* Handle negative offset */
+ ? (zend_long)Z_STRLEN_P(container) + offset : offset;
+ c = (zend_uchar)Z_STRVAL_P(container)[real_offset];
if (CG(one_char_string)[c]) {
ZVAL_INTERNED_STR(result, CG(one_char_string)[c]);
} else {
- ZVAL_NEW_STR(result, zend_string_init(Z_STRVAL_P(container) + offset, 1, 0));
+ ZVAL_NEW_STR(result, zend_string_init(Z_STRVAL_P(container) + real_offset, 1, 0));
}
}
} else if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
lval = Z_LVAL_P(offset);
ZEND_VM_C_LABEL(isset_str_offset):
+ if (UNEXPECTED(lval < 0)) { /* Handle negative offset */
+ lval += (zend_long)Z_STRLEN_P(container);
+ }
if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) {
if (opline->extended_value & ZEND_ISSET) {
result = 1;
if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
lval = Z_LVAL_P(offset);
isset_str_offset:
+ if (UNEXPECTED(lval < 0)) { /* Handle negative offset */
+ lval += (zend_long)Z_STRLEN_P(container);
+ }
if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) {
if (opline->extended_value & ZEND_ISSET) {
result = 1;
if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
lval = Z_LVAL_P(offset);
isset_str_offset:
+ if (UNEXPECTED(lval < 0)) { /* Handle negative offset */
+ lval += (zend_long)Z_STRLEN_P(container);
+ }
if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) {
if (opline->extended_value & ZEND_ISSET) {
result = 1;
if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
lval = Z_LVAL_P(offset);
isset_str_offset:
+ if (UNEXPECTED(lval < 0)) { /* Handle negative offset */
+ lval += (zend_long)Z_STRLEN_P(container);
+ }
if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) {
if (opline->extended_value & ZEND_ISSET) {
result = 1;
if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
lval = Z_LVAL_P(offset);
isset_str_offset:
+ if (UNEXPECTED(lval < 0)) { /* Handle negative offset */
+ lval += (zend_long)Z_STRLEN_P(container);
+ }
if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) {
if (opline->extended_value & ZEND_ISSET) {
result = 1;
if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
lval = Z_LVAL_P(offset);
isset_str_offset:
+ if (UNEXPECTED(lval < 0)) { /* Handle negative offset */
+ lval += (zend_long)Z_STRLEN_P(container);
+ }
if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) {
if (opline->extended_value & ZEND_ISSET) {
result = 1;
if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
lval = Z_LVAL_P(offset);
isset_str_offset:
+ if (UNEXPECTED(lval < 0)) { /* Handle negative offset */
+ lval += (zend_long)Z_STRLEN_P(container);
+ }
if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) {
if (opline->extended_value & ZEND_ISSET) {
result = 1;
if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
lval = Z_LVAL_P(offset);
isset_str_offset:
+ if (UNEXPECTED(lval < 0)) { /* Handle negative offset */
+ lval += (zend_long)Z_STRLEN_P(container);
+ }
if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) {
if (opline->extended_value & ZEND_ISSET) {
result = 1;
if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
lval = Z_LVAL_P(offset);
isset_str_offset:
+ if (UNEXPECTED(lval < 0)) { /* Handle negative offset */
+ lval += (zend_long)Z_STRLEN_P(container);
+ }
if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) {
if (opline->extended_value & ZEND_ISSET) {
result = 1;
if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
lval = Z_LVAL_P(offset);
isset_str_offset:
+ if (UNEXPECTED(lval < 0)) { /* Handle negative offset */
+ lval += (zend_long)Z_STRLEN_P(container);
+ }
if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) {
if (opline->extended_value & ZEND_ISSET) {
result = 1;
if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
lval = Z_LVAL_P(offset);
isset_str_offset:
+ if (UNEXPECTED(lval < 0)) { /* Handle negative offset */
+ lval += (zend_long)Z_STRLEN_P(container);
+ }
if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) {
if (opline->extended_value & ZEND_ISSET) {
result = 1;
if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
lval = Z_LVAL_P(offset);
isset_str_offset:
+ if (UNEXPECTED(lval < 0)) { /* Handle negative offset */
+ lval += (zend_long)Z_STRLEN_P(container);
+ }
if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) {
if (opline->extended_value & ZEND_ISSET) {
result = 1;
if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
lval = Z_LVAL_P(offset);
isset_str_offset:
+ if (UNEXPECTED(lval < 0)) { /* Handle negative offset */
+ lval += (zend_long)Z_STRLEN_P(container);
+ }
if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) {
if (opline->extended_value & ZEND_ISSET) {
result = 1;