Skip to content

Commit 67fdba0

Browse files
committed
Merge pull request #259
2 parents e9e8443 + 3c5363e commit 67fdba0

File tree

2 files changed

+116
-54
lines changed

2 files changed

+116
-54
lines changed

src/bson.c

Lines changed: 64 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1206,99 +1206,109 @@ PHONGO_API void phongo_zval_to_bson(zval *data, php_phongo_bson_flags_t flags, b
12061206

12071207
#if PHP_VERSION_ID >= 70000
12081208
{
1209-
zend_string *key;
1210-
zend_ulong num_key;
1211-
zval *value;
1212-
1213-
ZEND_HASH_FOREACH_KEY_VAL(ht_data, num_key, key, value) {
1214-
if (key) {
1215-
if (Z_TYPE_P(data) == IS_OBJECT) {
1216-
zend_string *member = NULL;
1217-
1218-
/* Ignore non-public properties */
1219-
if (!instanceof_function(Z_OBJCE_P(data), php_phongo_serializable_ce) &&
1220-
!is_public_property(Z_OBJCE_P(data), key, &member TSRMLS_CC)) {
1221-
if (member) {
1222-
zend_string_release(member);
1223-
}
1224-
continue;
1225-
}
1226-
1227-
if (flags & PHONGO_BSON_ADD_ID) {
1228-
if (!strncmp(member ? ZSTR_VAL(member) : ZSTR_VAL(key), "_id", sizeof("_id")-1)) {
1229-
flags &= ~PHONGO_BSON_ADD_ID;
1230-
}
1231-
}
1209+
zend_string *string_key = NULL;
1210+
zend_ulong num_key = 0;
1211+
zval *value;
1212+
1213+
ZEND_HASH_FOREACH_KEY_VAL(ht_data, num_key, string_key, value) {
1214+
/* Ensure we're working with a string key */
1215+
if (!string_key) {
1216+
string_key = zend_long_to_str(num_key);
1217+
} else {
1218+
zend_string_addref(string_key);
1219+
}
12321220

1233-
phongo_bson_append(bson, flags & ~PHONGO_BSON_ADD_ID,
1234-
member ? ZSTR_VAL(member) : ZSTR_VAL(key),
1235-
member ? ZSTR_LEN(member) : ZSTR_LEN(key),
1236-
value TSRMLS_CC);
1221+
if (Z_TYPE_P(data) == IS_OBJECT) {
1222+
zend_string *member = NULL;
12371223

1224+
/* Ignore non-public properties */
1225+
if (!instanceof_function(Z_OBJCE_P(data), php_phongo_serializable_ce) &&
1226+
!is_public_property(Z_OBJCE_P(data), string_key, &member TSRMLS_CC)) {
12381227
if (member) {
12391228
zend_string_release(member);
12401229
}
1241-
} else {
1242-
if (flags & PHONGO_BSON_ADD_ID) {
1243-
if (!strncmp(ZSTR_VAL(key), "_id", sizeof("_id")-1)) {
1244-
flags &= ~PHONGO_BSON_ADD_ID;
1245-
}
1230+
zend_string_release(string_key);
1231+
continue;
1232+
}
1233+
1234+
if (flags & PHONGO_BSON_ADD_ID) {
1235+
if (!strncmp(member ? ZSTR_VAL(member) : ZSTR_VAL(string_key), "_id", sizeof("_id")-1)) {
1236+
flags &= ~PHONGO_BSON_ADD_ID;
12461237
}
1247-
phongo_bson_append(bson, flags & ~PHONGO_BSON_ADD_ID, ZSTR_VAL(key), ZSTR_LEN(key), value TSRMLS_CC);
1238+
}
1239+
1240+
phongo_bson_append(bson, flags & ~PHONGO_BSON_ADD_ID,
1241+
member ? ZSTR_VAL(member) : ZSTR_VAL(string_key),
1242+
member ? ZSTR_LEN(member) : ZSTR_LEN(string_key),
1243+
value TSRMLS_CC);
1244+
1245+
if (member) {
1246+
zend_string_release(member);
12481247
}
12491248
} else {
1250-
char numbuf[32];
1251-
const char *skey;
1252-
unsigned int skey_len = 0;
1253-
skey_len = bson_uint32_to_string(num_key, (const char **)&skey, numbuf, sizeof(numbuf));
1254-
phongo_bson_append(bson, flags & ~PHONGO_BSON_ADD_ID, skey, skey_len, value TSRMLS_CC);
1249+
if (flags & PHONGO_BSON_ADD_ID) {
1250+
if (!strncmp(ZSTR_VAL(string_key), "_id", sizeof("_id")-1)) {
1251+
flags &= ~PHONGO_BSON_ADD_ID;
1252+
}
1253+
}
1254+
phongo_bson_append(bson, flags & ~PHONGO_BSON_ADD_ID, ZSTR_VAL(string_key), ZSTR_LEN(string_key), value TSRMLS_CC);
12551255
}
1256+
1257+
zend_string_release(string_key);
12561258
} ZEND_HASH_FOREACH_END();
12571259
}
12581260
#else
12591261
zend_hash_internal_pointer_reset_ex(ht_data, &pos);
12601262
for (;; zend_hash_move_forward_ex(ht_data, &pos)) {
1261-
unsigned int key_len = 0;
1262-
uint64_t index = 0;
1263-
char numbuf[32];
1264-
char *key = NULL;
1265-
zval **entry;
1266-
int hash_type = HASH_KEY_NON_EXISTENT;
1263+
char *string_key = NULL;
1264+
uint string_key_len = 0;
1265+
ulong num_key = 0;
1266+
zval **value;
1267+
int hash_type;
12671268

1268-
hash_type = zend_hash_get_current_key_ex(ht_data, &key, &key_len, &index, 0, &pos);
1269+
hash_type = zend_hash_get_current_key_ex(ht_data, &string_key, &string_key_len, &num_key, 0, &pos);
12691270

12701271
if (hash_type == HASH_KEY_NON_EXISTENT) {
12711272
break;
12721273
}
12731274

1274-
if (zend_hash_get_current_data_ex(ht_data, (void **) &entry, &pos) == FAILURE) {
1275+
if (zend_hash_get_current_data_ex(ht_data, (void **) &value, &pos) == FAILURE) {
12751276
break;
12761277
}
12771278

12781279
if (hash_type == HASH_KEY_IS_STRING) {
12791280
if (ht_data_from_properties) {
12801281
const char *class_name;
1281-
zend_unmangle_property_name(key, key_len-1, &class_name, (const char **)&key);
1282-
key_len = strlen(key);
1282+
zend_unmangle_property_name(string_key, string_key_len-1, &class_name, (const char **)&string_key);
1283+
string_key_len = strlen(string_key);
12831284

12841285
/* Ignore non-public properties */
1285-
if (!is_public_property(Z_OBJCE_P(data), key, key_len TSRMLS_CC)) {
1286+
if (!is_public_property(Z_OBJCE_P(data), string_key, string_key_len TSRMLS_CC)) {
12861287
continue;
12871288
}
12881289
} else {
12891290
/* Chop off the \0 from string lengths */
1290-
key_len -= 1;
1291+
string_key_len -= 1;
12911292
}
12921293

12931294
if (flags & PHONGO_BSON_ADD_ID) {
1294-
if (!strncmp(key, "_id", sizeof("_id")-1)) {
1295+
if (!strncmp(string_key, "_id", sizeof("_id")-1)) {
12951296
flags &= ~PHONGO_BSON_ADD_ID;
12961297
}
12971298
}
1298-
} else {
1299-
key_len = bson_uint32_to_string(index, (const char **)&key, numbuf, sizeof(numbuf));
13001299
}
1301-
phongo_bson_append(bson, flags & ~PHONGO_BSON_ADD_ID, key, key_len, *entry TSRMLS_CC);
1300+
1301+
/* Ensure we're working with a string key */
1302+
if (hash_type == HASH_KEY_IS_LONG) {
1303+
spprintf(&string_key, 0, "%ld", num_key);
1304+
string_key_len = strlen(string_key);
1305+
}
1306+
1307+
phongo_bson_append(bson, flags & ~PHONGO_BSON_ADD_ID, string_key, string_key_len, *value TSRMLS_CC);
1308+
1309+
if (hash_type == HASH_KEY_IS_LONG) {
1310+
efree(string_key);
1311+
}
13021312
}
13031313
#endif
13041314

tests/bson/bug0623.phpt

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
--TEST--
2+
PHPC-623: Numeric keys limited to unsigned 32-bit integer
3+
--SKIPIF--
4+
<?php if (8 !== PHP_INT_SIZE) { die('skip Only for 64-bit platform'); } ?>
5+
<?php require __DIR__ . "/../utils/basic-skipif.inc"?>
6+
--INI--
7+
mongodb.debug=stderr
8+
--FILE--
9+
<?php
10+
11+
require_once __DIR__ . "/../utils/basic.inc";
12+
13+
$tests = [
14+
[
15+
'9781449410247' => 'a',
16+
'X9781449410247' => 'b',
17+
9781449410248 => 'c',
18+
],
19+
[
20+
'4294967295' => 'a',
21+
'4294967296' => 'b',
22+
'4294967297' => 'c',
23+
]
24+
];
25+
26+
foreach ($tests as $test) {
27+
printf("Test %s\n", json_encode($test));
28+
$bson = fromPHP($test);
29+
hex_dump($bson);
30+
echo toJSON($bson), "\n\n";
31+
}
32+
33+
?>
34+
===DONE===
35+
<?php exit(0); ?>
36+
--EXPECTF--
37+
Test {"9781449410247":"a","X9781449410247":"b","9781449410248":"c"}
38+
0 : 45 00 00 00 02 39 37 38 31 34 34 39 34 31 30 32 [E....97814494102]
39+
10 : 34 37 00 02 00 00 00 61 00 02 58 39 37 38 31 34 [47.....a..X97814]
40+
20 : 34 39 34 31 30 32 34 37 00 02 00 00 00 62 00 02 [49410247.....b..]
41+
30 : 39 37 38 31 34 34 39 34 31 30 32 34 38 00 02 00 [9781449410248...]
42+
40 : 00 00 63 00 00 [..c..]
43+
{ "9781449410247" : "a", "X9781449410247" : "b", "9781449410248" : "c" }
44+
45+
Test {"4294967295":"a","4294967296":"b","4294967297":"c"}
46+
0 : 3b 00 00 00 02 34 32 39 34 39 36 37 32 39 35 00 [;....4294967295.]
47+
10 : 02 00 00 00 61 00 02 34 32 39 34 39 36 37 32 39 [....a..429496729]
48+
20 : 36 00 02 00 00 00 62 00 02 34 32 39 34 39 36 37 [6.....b..4294967]
49+
30 : 32 39 37 00 02 00 00 00 63 00 00 [297.....c..]
50+
{ "4294967295" : "a", "4294967296" : "b", "4294967297" : "c" }
51+
52+
===DONE===

0 commit comments

Comments
 (0)