Skip to content

Commit 4b484df

Browse files
committed
Merge pull request #117
2 parents de38169 + 12265c8 commit 4b484df

File tree

6 files changed

+191
-54
lines changed

6 files changed

+191
-54
lines changed

php_phongo.c

Lines changed: 73 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -316,82 +316,106 @@ void phongo_writeconcern_init(zval *return_value, const mongoc_write_concern_t *
316316
}
317317
/* }}} */
318318

319-
bool phongo_query_init(php_phongo_query_t *query, zval *filter, zval *options TSRMLS_DC) /* {{{ */
319+
int32_t phongo_bson_find_as_int32(bson_t *bson, const char *key, int32_t fallback)
320320
{
321-
zval *zquery = NULL;
321+
bson_iter_t iter;
322322

323-
if (!(Z_TYPE_P(filter) == IS_ARRAY || Z_TYPE_P(filter) == IS_OBJECT)) {
324-
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Expected filter to be array or object, %s given", zend_get_type_by_const(Z_TYPE_P(filter)));
325-
return false;
323+
if (bson_iter_init_find(&iter, bson, key) && BSON_ITER_HOLDS_INT32(&iter)) {
324+
return bson_iter_int32(&iter);
326325
}
327-
convert_to_object(filter);
328326

329-
MAKE_STD_ZVAL(zquery);
330-
array_init(zquery);
327+
return fallback;
328+
}
331329

332-
if (options) {
333-
/* TODO: Ensure batchSize, limit, and skip are 32-bit */
334-
query->batch_size = php_array_fetchc_long(options, "batchSize");
335-
query->limit = php_array_fetchc_long(options, "limit");
336-
query->skip = php_array_fetchc_long(options, "skip");
330+
bool phongo_bson_find_as_bool(bson_t *bson, const char *key, bool fallback)
331+
{
332+
bson_iter_t iter;
337333

338-
query->flags = 0;
339-
query->flags |= php_array_fetchl_bool(options, ZEND_STRS("tailable")) ? MONGOC_QUERY_TAILABLE_CURSOR : 0;
340-
query->flags |= php_array_fetchl_bool(options, ZEND_STRS("slaveOk")) ? MONGOC_QUERY_SLAVE_OK : 0;
341-
query->flags |= php_array_fetchl_bool(options, ZEND_STRS("oplogReplay")) ? MONGOC_QUERY_OPLOG_REPLAY : 0;
342-
query->flags |= php_array_fetchl_bool(options, ZEND_STRS("noCursorTimeout")) ? MONGOC_QUERY_NO_CURSOR_TIMEOUT : 0;
343-
query->flags |= php_array_fetchl_bool(options, ZEND_STRS("awaitData")) ? MONGOC_QUERY_AWAIT_DATA : 0;
344-
query->flags |= php_array_fetchl_bool(options, ZEND_STRS("exhaust")) ? MONGOC_QUERY_EXHAUST : 0;
345-
query->flags |= php_array_fetchl_bool(options, ZEND_STRS("partial")) ? MONGOC_QUERY_PARTIAL : 0;
334+
if (bson_iter_init_find(&iter, bson, key) && BSON_ITER_HOLDS_BOOL(&iter)) {
335+
return bson_iter_bool(&iter);
336+
}
337+
338+
return fallback;
339+
}
346340

341+
void phongo_bson_iter_as_document(const bson_iter_t *iter, uint32_t *document_len, const uint8_t **document)
342+
{
343+
*document = NULL;
344+
*document_len = 0;
345+
346+
if (BSON_ITER_HOLDS_DOCUMENT(iter) || BSON_ITER_HOLDS_ARRAY(iter)) {
347+
memcpy (document_len, (iter->raw + iter->d1), sizeof (*document_len));
348+
*document_len = BSON_UINT32_FROM_LE (*document_len);
349+
*document = (iter->raw + iter->d1);
350+
}
351+
}
352+
353+
bool phongo_query_init(php_phongo_query_t *query, bson_t *filter, bson_t *options TSRMLS_DC) /* {{{ */
354+
{
355+
bson_iter_t iter;
347356

348-
if (php_array_existsc(options, "modifiers")) {
349-
zval *modifiers = php_array_fetchc(options, "modifiers");
357+
if (options) {
358+
query->batch_size = phongo_bson_find_as_int32(options, "batchSize", 0);
359+
query->limit = phongo_bson_find_as_int32(options, "limit", 0);
360+
query->skip = phongo_bson_find_as_int32(options, "skip", 0);
350361

351-
if (modifiers && !(Z_TYPE_P(modifiers) == IS_ARRAY || Z_TYPE_P(modifiers) == IS_OBJECT)) {
352-
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Expected modifiers to be array or object, %s given", zend_get_type_by_const(Z_TYPE_P(modifiers)));
353-
zval_ptr_dtor(&zquery);
362+
query->flags = 0;
363+
query->flags |= phongo_bson_find_as_bool(options, "tailable", false) ? MONGOC_QUERY_TAILABLE_CURSOR : 0;
364+
query->flags |= phongo_bson_find_as_bool(options, "slaveOk", false) ? MONGOC_QUERY_SLAVE_OK : 0;
365+
query->flags |= phongo_bson_find_as_bool(options, "oplogReplay", false) ? MONGOC_QUERY_OPLOG_REPLAY : 0;
366+
query->flags |= phongo_bson_find_as_bool(options, "noCursorTimeout", false) ? MONGOC_QUERY_NO_CURSOR_TIMEOUT : 0;
367+
query->flags |= phongo_bson_find_as_bool(options, "awaitData", false) ? MONGOC_QUERY_AWAIT_DATA : 0;
368+
query->flags |= phongo_bson_find_as_bool(options, "exhaust", false) ? MONGOC_QUERY_EXHAUST : 0;
369+
query->flags |= phongo_bson_find_as_bool(options, "partial", false) ? MONGOC_QUERY_PARTIAL : 0;
370+
371+
372+
if (bson_iter_init_find(&iter, options, "modifiers")) {
373+
bson_t tmp;
374+
uint32_t len = 0;
375+
const uint8_t *data = NULL;
376+
377+
if (! (BSON_ITER_HOLDS_DOCUMENT (&iter) || BSON_ITER_HOLDS_ARRAY (&iter))) {
378+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Expected modifiers to be array or object, %d given", bson_iter_type(&iter));
354379
return false;
355380
}
356381

357-
zend_hash_merge(HASH_OF(zquery), HASH_OF(modifiers), (void (*)(void*))zval_add_ref, NULL, sizeof(zval *), 1);
382+
bson_iter_document(&iter, &len, &data);
383+
bson_init_static(&tmp, data, len);
384+
bson_copy_to_excluding_noinit(&tmp, query->query, "nadastrada", NULL);
385+
bson_destroy (&tmp);
358386
}
359387

360-
if (php_array_existsc(options, "projection")) {
361-
zval *projection = php_array_fetchc(options, "projection");
388+
if (bson_iter_init_find(&iter, options, "projection")) {
389+
uint32_t len = 0;
390+
const uint8_t *data = NULL;
362391

363-
if (projection && !(Z_TYPE_P(projection) == IS_ARRAY || Z_TYPE_P(projection) == IS_OBJECT)) {
364-
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Expected projection to be array or object, %s given", zend_get_type_by_const(Z_TYPE_P(projection)));
365-
zval_ptr_dtor(&zquery);
392+
if (! (BSON_ITER_HOLDS_DOCUMENT (&iter) || BSON_ITER_HOLDS_ARRAY (&iter))) {
393+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Expected projection to be array or object, %d given", bson_iter_type(&iter));
366394
return false;
367395
}
368396

369-
query->selector = bson_new();
370-
zval_to_bson(projection, PHONGO_BSON_NONE, query->selector, NULL TSRMLS_CC);
397+
bson_iter_document(&iter, &len, &data);
398+
query->selector = bson_new_from_data(data, len);
371399
}
372400

373-
if (php_array_existsc(options, "sort")) {
374-
zval *sort = php_array_fetchc(options, "sort");
401+
if (bson_iter_init_find(&iter, options, "sort")) {
402+
bson_t tmp;
403+
uint32_t len = 0;
404+
const uint8_t *data = NULL;
375405

376-
if (sort && !(Z_TYPE_P(sort) == IS_ARRAY || Z_TYPE_P(sort) == IS_OBJECT)) {
377-
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Expected sort to be array or object, %s given", zend_get_type_by_const(Z_TYPE_P(sort)));
378-
zval_ptr_dtor(&zquery);
406+
if (! (BSON_ITER_HOLDS_DOCUMENT (&iter) || BSON_ITER_HOLDS_ARRAY (&iter))) {
407+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Expected sort to be array or object, %d given", bson_iter_type(&iter));
379408
return false;
380409
}
381410

382-
convert_to_object_ex(&sort);
383-
Z_ADDREF_P(sort);
384-
add_assoc_zval_ex(zquery, ZEND_STRS("$orderby"), sort);
411+
phongo_bson_iter_as_document(&iter, &len, &data);
412+
bson_init_static(&tmp, data, len);
413+
bson_append_document(query->query, "$orderby", -1, &tmp);
414+
bson_destroy(&tmp);
385415
}
386416
}
387417

388-
Z_ADDREF_P(filter);
389-
add_assoc_zval_ex(zquery, ZEND_STRS("$query"), filter);
390-
391-
query->query = bson_new();
392-
zval_to_bson(zquery, PHONGO_BSON_NONE, query->query, NULL TSRMLS_CC);
393-
zval_ptr_dtor(&zquery);
394-
418+
BSON_APPEND_DOCUMENT(query->query, "$query", filter);
395419
return true;
396420
} /* }}} */
397421

php_phongo.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ PHONGO_API zend_object_handlers *phongo_get_std_object_handlers(void);
114114
void phongo_server_init (zval *return_value, mongoc_client_t *client, int server_id TSRMLS_DC);
115115
void phongo_readpreference_init (zval *return_value, const mongoc_read_prefs_t *read_prefs TSRMLS_DC);
116116
void phongo_writeconcern_init (zval *return_value, const mongoc_write_concern_t *write_concern TSRMLS_DC);
117-
bool phongo_query_init (php_phongo_query_t *query, zval *filter, zval *options TSRMLS_DC);
117+
bool phongo_query_init (php_phongo_query_t *query, bson_t *filter, bson_t *options TSRMLS_DC);
118118
mongoc_bulk_operation_t* phongo_bulkwrite_init (zend_bool ordered);
119119
bool phongo_execute_write (mongoc_client_t *client, const char *namespace, mongoc_bulk_operation_t *bulk, const mongoc_write_concern_t *write_concern, int server_id, zval *return_value, int return_value_used TSRMLS_DC);
120120
int phongo_execute_command (mongoc_client_t *client, const char *db, const bson_t *command, const mongoc_read_prefs_t *read_preference, int server_id, zval *return_value, int return_value_used TSRMLS_DC);

src/MongoDB/Query.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,22 +52,37 @@ PHP_METHOD(Query, __construct)
5252
{
5353
php_phongo_query_t *intern;
5454
zend_error_handling error_handling;
55-
zval *filter;
56-
zval *options = NULL;
55+
zval *zfilter;
56+
zval *zoptions = NULL;
57+
bson_t bfilter;
58+
bson_t boptions = BSON_INITIALIZER;
5759
(void)return_value_ptr; (void)return_value; (void)return_value_used;
5860

5961

6062
zend_replace_error_handling(EH_THROW, phongo_exception_from_phongo_domain(PHONGO_ERROR_INVALID_ARGUMENT), &error_handling TSRMLS_CC);
6163
intern = (php_phongo_query_t *)zend_object_store_get_object(getThis() TSRMLS_CC);
6264

63-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "A|a!", &filter, &options) == FAILURE) {
65+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "A|a!", &zfilter, &zoptions) == FAILURE) {
6466
zend_restore_error_handling(&error_handling TSRMLS_CC);
6567
return;
6668
}
6769
zend_restore_error_handling(&error_handling TSRMLS_CC);
6870

6971

70-
phongo_query_init(intern, filter, options TSRMLS_CC);
72+
intern->query = bson_new();
73+
74+
bson_init(&bfilter);
75+
zval_to_bson(zfilter, PHONGO_BSON_NONE, &bfilter, NULL TSRMLS_CC);
76+
77+
if (zoptions) {
78+
bson_init(&boptions);
79+
zval_to_bson(zoptions, PHONGO_BSON_NONE, &boptions, NULL TSRMLS_CC);
80+
}
81+
if (!phongo_query_init(intern, &bfilter, &boptions TSRMLS_CC)) {
82+
bson_clear(&intern->query);
83+
}
84+
bson_destroy(&bfilter);
85+
bson_destroy(&boptions);
7186
}
7287
/* }}} */
7388

tests/query/bug0430-001.phpt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
--TEST--
2+
PHPC-430: Query constructor arguments are modified
3+
--SKIPIF--
4+
<?php require __DIR__ . "/../utils/basic-skipif.inc"?>
5+
--FILE--
6+
<?php
7+
require_once __DIR__ . "/../utils/basic.inc";
8+
9+
$filter = [];
10+
$options = ['sort' => ['x' => 1]];
11+
$query = new MongoDB\Driver\Query($filter, $options);
12+
13+
var_dump($filter);
14+
var_dump($options);
15+
16+
?>
17+
===DONE===
18+
<?php exit(0); ?>
19+
--EXPECT--
20+
array(0) {
21+
}
22+
array(1) {
23+
["sort"]=>
24+
array(1) {
25+
["x"]=>
26+
int(1)
27+
}
28+
}
29+
===DONE===

tests/query/bug0430-002.phpt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
--TEST--
2+
PHPC-430: Query constructor arguments are modified
3+
--SKIPIF--
4+
<?php require __DIR__ . "/../utils/basic-skipif.inc"?>
5+
--FILE--
6+
<?php
7+
require_once __DIR__ . "/../utils/basic.inc";
8+
9+
$options = ['sort' => ['x' => 1]];
10+
11+
$optionsCopy = $options;
12+
$optionsCopy['cursorFlags'] = 0;
13+
14+
$query = new MongoDB\Driver\Query([], $options);
15+
16+
var_dump($options);
17+
var_dump($optionsCopy);
18+
19+
?>
20+
===DONE===
21+
<?php exit(0); ?>
22+
--EXPECT--
23+
array(1) {
24+
["sort"]=>
25+
array(1) {
26+
["x"]=>
27+
int(1)
28+
}
29+
}
30+
array(2) {
31+
["sort"]=>
32+
array(1) {
33+
["x"]=>
34+
int(1)
35+
}
36+
["cursorFlags"]=>
37+
int(0)
38+
}
39+
===DONE===

tests/query/bug0430-003.phpt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--TEST--
2+
PHPC-430: Query constructor arguments are modified
3+
--SKIPIF--
4+
<?php require __DIR__ . "/../utils/basic-skipif.inc"?>
5+
--FILE--
6+
<?php
7+
require_once __DIR__ . "/../utils/basic.inc";
8+
9+
function buildQuery($filter, $options)
10+
{
11+
$options["cursorFlags"] = 0;
12+
return new MongoDB\Driver\Query($filter, $options);
13+
}
14+
15+
$filter = [];
16+
$options = ['sort' => []];
17+
$query = buildQuery($filter, $options);
18+
19+
var_dump($options);
20+
21+
?>
22+
===DONE===
23+
<?php exit(0); ?>
24+
--EXPECT--
25+
array(1) {
26+
["sort"]=>
27+
array(0) {
28+
}
29+
}
30+
===DONE===

0 commit comments

Comments
 (0)