Skip to content

Commit caa518e

Browse files
committed
Merge pull request #618
2 parents 1a1f537 + 98d3e02 commit caa518e

File tree

733 files changed

+1368
-1131
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

733 files changed

+1368
-1131
lines changed

config.m4

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ if test "$MONGODB" != "no"; then
168168
src/BSON/TypeWrapper.c \
169169
src/BSON/Unserializable.c \
170170
src/BSON/UTCDateTime.c \
171+
src/BSON/functions.c \
171172
src/MongoDB/BulkWrite.c \
172173
src/MongoDB/Command.c \
173174
src/MongoDB/Cursor.c \

config.w32

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ if (PHP_MONGODB != "no") {
8484

8585
EXTENSION("mongodb", "php_phongo.c phongo_compat.c", null, PHP_MONGODB_CFLAGS);
8686
ADD_SOURCES(configure_module_dirname + "/src", "bson.c bson-encode.c", "mongodb");
87-
ADD_SOURCES(configure_module_dirname + "/src/BSON", "Binary.c Decimal128.c Javascript.c MaxKey.c MinKey.c ObjectID.c Persistable.c Regex.c Serializable.c Timestamp.c Type.c TypeWrapper.c Unserializable.c UTCDateTime.c", "mongodb");
87+
ADD_SOURCES(configure_module_dirname + "/src/BSON", "Binary.c Decimal128.c Javascript.c MaxKey.c MinKey.c ObjectID.c Persistable.c Regex.c Serializable.c Timestamp.c Type.c TypeWrapper.c Unserializable.c UTCDateTime.c functions.c", "mongodb");
8888
ADD_SOURCES(configure_module_dirname + "/src/MongoDB", "BulkWrite.c Command.c Cursor.c CursorId.c Manager.c Query.c ReadConcern.c ReadPreference.c Server.c WriteConcern.c WriteConcernError.c WriteError.c WriteResult.c", "mongodb");
8989
ADD_SOURCES(configure_module_dirname + "/src/MongoDB/Exception", "AuthenticationException.c BulkWriteException.c ConnectionException.c ConnectionTimeoutException.c Exception.c ExecutionTimeoutException.c InvalidArgumentException.c LogicException.c RuntimeException.c SSLConnectionException.c UnexpectedValueException.c WriteException.c", "mongodb");
9090
ADD_SOURCES(configure_module_dirname + "/src/MongoDB/Monitoring", "CommandFailedEvent.c CommandStartedEvent.c CommandSubscriber.c CommandSucceededEvent.c Subscriber.c functions.c", "mongodb");

php_bson.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,6 @@ bool php_phongo_bson_to_zval(const unsigned char *data, int data_len, zval **out
8484
#endif
8585
bool php_phongo_bson_typemap_to_state(zval *typemap, php_phongo_bson_typemap *map TSRMLS_DC);
8686

87-
PHP_FUNCTION(MongoDB_BSON_toPHP);
88-
PHP_FUNCTION(MongoDB_BSON_fromPHP);
89-
PHP_FUNCTION(MongoDB_BSON_toJSON);
90-
PHP_FUNCTION(MongoDB_BSON_toExtendedJSON);
91-
PHP_FUNCTION(MongoDB_BSON_fromJSON);
92-
9387
#endif /* PHONGO_BSON_H */
9488

9589

php_phongo.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
/* Our stuffz */
6868
#include "php_phongo.h"
6969
#include "php_bson.h"
70+
#include "src/BSON/functions.h"
7071
#include "src/MongoDB/Monitoring/functions.h"
7172

7273
#undef MONGOC_LOG_DOMAIN
@@ -2402,10 +2403,6 @@ ZEND_BEGIN_ARG_INFO_EX(ai_bson_toJSON, 0, 0, 1)
24022403
ZEND_ARG_INFO(0, bson)
24032404
ZEND_END_ARG_INFO();
24042405

2405-
ZEND_BEGIN_ARG_INFO_EX(ai_bson_toExtendedJSON, 0, 0, 1)
2406-
ZEND_ARG_INFO(0, bson)
2407-
ZEND_END_ARG_INFO();
2408-
24092406
ZEND_BEGIN_ARG_INFO_EX(ai_bson_fromJSON, 0, 0, 1)
24102407
ZEND_ARG_INFO(0, json)
24112408
ZEND_END_ARG_INFO();
@@ -2418,7 +2415,8 @@ static const zend_function_entry mongodb_functions[] = {
24182415
ZEND_NS_NAMED_FE("MongoDB\\BSON", fromPHP, PHP_FN(MongoDB_BSON_fromPHP), ai_bson_fromPHP)
24192416
ZEND_NS_NAMED_FE("MongoDB\\BSON", toPHP, PHP_FN(MongoDB_BSON_toPHP), ai_bson_toPHP)
24202417
ZEND_NS_NAMED_FE("MongoDB\\BSON", toJSON, PHP_FN(MongoDB_BSON_toJSON), ai_bson_toJSON)
2421-
ZEND_NS_NAMED_FE("MongoDB\\BSON", toExtendedJSON, PHP_FN(MongoDB_BSON_toExtendedJSON), ai_bson_toExtendedJSON)
2418+
ZEND_NS_NAMED_FE("MongoDB\\BSON", toCanonicalJSON, PHP_FN(MongoDB_BSON_toCanonicalJSON), ai_bson_toJSON)
2419+
ZEND_NS_NAMED_FE("MongoDB\\BSON", toRelaxedJSON, PHP_FN(MongoDB_BSON_toRelaxedJSON), ai_bson_toJSON)
24222420
ZEND_NS_NAMED_FE("MongoDB\\BSON", fromJSON, PHP_FN(MongoDB_BSON_fromJSON), ai_bson_fromJSON)
24232421
ZEND_NS_NAMED_FE("MongoDB\\Driver\\Monitoring", addSubscriber, PHP_FN(MongoDB_Driver_Monitoring_addSubscriber), ai_mongodb_driver_monitoring_subscriber)
24242422
ZEND_NS_NAMED_FE("MongoDB\\Driver\\Monitoring", removeSubscriber, PHP_FN(MongoDB_Driver_Monitoring_removeSubscriber), ai_mongodb_driver_monitoring_subscriber)

scripts/convert-bson-corpus-tests.php

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@
22

33
require_once __DIR__ . '/../tests/utils/tools.php';
44

5+
$expectedFailures = [
6+
'Double type: 1.23456789012345677E+18' => 'Variation in double\'s string representation (SPEC-850)',
7+
'Double type: -1.23456789012345677E+18' => 'Variation in double\'s string representation (SPEC-850)',
8+
'Int64 type: -1' => 'PHP encodes integers as 32-bit if range allows',
9+
'Int64 type: 0' => 'PHP encodes integers as 32-bit if range allows',
10+
'Int64 type: 1' => 'PHP encodes integers as 32-bit if range allows',
11+
'Javascript Code with Scope: bad scope doc (field has bad string length)' => 'Depends on PHPC-889',
12+
'Javascript Code with Scope: Unicode and embedded null in code string, empty scope' => 'Embedded null in code string is not supported in libbson (CDRIVER-1879)',
13+
'Multiple types within the same document: All BSON types' => 'PHP encodes integers as 32-bit if range allows',
14+
'Top-level document validity: Bad $date (number, not string or hash)' => 'Legacy extended JSON $date syntax uses numbers (CDRIVER-2223)',
15+
];
16+
517
$outputPath = realpath(__DIR__ . '/../tests') . '/bson-corpus/';
618

719
if ( ! is_dir($outputPath) && ! mkdir($outputPath, 0755, true)) {
@@ -35,7 +47,7 @@
3547
foreach ($test['valid'] as $i => $case) {
3648
$outputFile = sprintf('%s-valid-%03d.phpt', pathinfo($inputFile, PATHINFO_FILENAME), $i + 1);
3749
try {
38-
$output = renderPhpt(getParamsForValid($test, $case));
50+
$output = renderPhpt(getParamsForValid($test, $case), $expectedFailures);
3951
} catch (Exception $e) {
4052
printf("Error processing valid[%d] in %s: %s\n", $i, $inputFile, $e->getMessage());
4153
continue;
@@ -52,7 +64,7 @@
5264
foreach ($test['decodeErrors'] as $i => $case) {
5365
$outputFile = sprintf('%s-decodeError-%03d.phpt', pathinfo($inputFile, PATHINFO_FILENAME), $i + 1);
5466
try {
55-
$output = renderPhpt(getParamsForDecodeError($test, $case));
67+
$output = renderPhpt(getParamsForDecodeError($test, $case), $expectedFailures);
5668
} catch (Exception $e) {
5769
printf("Error processing decodeErrors[%d] in %s: %s\n", $i, $inputFile, $e->getMessage());
5870
continue;
@@ -69,7 +81,7 @@
6981
foreach ($test['parseErrors'] as $i => $case) {
7082
$outputFile = sprintf('%s-parseError-%03d.phpt', pathinfo($inputFile, PATHINFO_FILENAME), $i + 1);
7183
try {
72-
$output = renderPhpt(getParamsForParseError($test, $case));
84+
$output = renderPhpt(getParamsForParseError($test, $case), $expectedFailures);
7385
} catch (Exception $e) {
7486
printf("Error processing parseErrors[%d] in %s: %s\n", $i, $inputFile, $e->getMessage());
7587
continue;
@@ -139,12 +151,12 @@ function getParamsForValid(array $test, array $case)
139151
$expect .= $expectedCanonicalBson . "\n";
140152

141153
$code .= "\n// Canonical BSON -> Canonical extJSON \n";
142-
$code .= 'echo json_canonicalize(toExtendedJSON($canonicalBson)), "\n";' . "\n";;
154+
$code .= 'echo json_canonicalize(toCanonicalJSON($canonicalBson)), "\n";' . "\n";;
143155
$expect .= $expectedCanonicalExtJson . "\n";
144156

145157
if (isset($relaxedExtJson)) {
146158
$code .= "\n// Canonical BSON -> Relaxed extJSON \n";
147-
$code .= 'echo json_canonicalize(toJSON($canonicalBson)), "\n";' . "\n";;
159+
$code .= 'echo json_canonicalize(toRelaxedJSON($canonicalBson)), "\n";' . "\n";;
148160
$expect .= $expectedRelaxedExtJson . "\n";
149161
}
150162

@@ -160,12 +172,12 @@ function getParamsForValid(array $test, array $case)
160172
$expect .= $expectedCanonicalBson . "\n";
161173

162174
$code .= "\n// Degenerate BSON -> Canonical extJSON \n";
163-
$code .= 'echo json_canonicalize(toExtendedJSON($degenerateBson)), "\n";' . "\n";;
175+
$code .= 'echo json_canonicalize(toCanonicalJSON($degenerateBson)), "\n";' . "\n";;
164176
$expect .= $expectedCanonicalExtJson . "\n";
165177

166178
if (isset($relaxedExtJson)) {
167179
$code .= "\n// Degenerate BSON -> Relaxed extJSON \n";
168-
$code .= 'echo json_canonicalize(toJSON($degenerateBson)), "\n";' . "\n";;
180+
$code .= 'echo json_canonicalize(toRelaxedJSON($degenerateBson)), "\n";' . "\n";;
169181
$expect .= $expectedRelaxedExtJson . "\n";
170182
}
171183
}
@@ -178,7 +190,7 @@ function getParamsForValid(array $test, array $case)
178190

179191
if (isset($relaxedExtJson)) {
180192
$code .= "\n// Relaxed extJSON -> BSON -> Relaxed extJSON \n";
181-
$code .= 'echo json_canonicalize(toJSON(fromJSON($relaxedExtJson))), "\n";' . "\n";
193+
$code .= 'echo json_canonicalize(toRelaxedJSON(fromJSON($relaxedExtJson))), "\n";' . "\n";
182194
$expect .= $expectedRelaxedExtJson . "\n";
183195
}
184196

@@ -256,12 +268,16 @@ function getParamsForParseError(array $test, array $case)
256268
];
257269
}
258270

259-
function renderPhpt(array $params)
271+
function renderPhpt(array $params, array $expectedFailures)
260272
{
273+
$params['%XFAIL%'] = isset($expectedFailures[$params['%NAME%']])
274+
? "--XFAIL--\n" . $expectedFailures[$params['%NAME%']] . "\n"
275+
: '';
276+
261277
$template = <<< 'TEMPLATE'
262278
--TEST--
263279
%NAME%
264-
--DESCRIPTION--
280+
%XFAIL%--DESCRIPTION--
265281
Generated by scripts/convert-bson-corpus-tests.php
266282
267283
DO NOT EDIT THIS FILE

src/BSON/functions.c

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
/*
2+
* Copyright 2014-2017 MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifdef HAVE_CONFIG_H
18+
# include "config.h"
19+
#endif
20+
21+
#include <php.h>
22+
#include "phongo_compat.h"
23+
#include "php_phongo.h"
24+
#include "php_bson.h"
25+
26+
typedef enum {
27+
PHONGO_JSON_MODE_LEGACY,
28+
PHONGO_JSON_MODE_CANONICAL,
29+
PHONGO_JSON_MODE_RELAXED,
30+
} php_phongo_json_mode_t;
31+
32+
/* {{{ proto string MongoDB\BSON\fromPHP(array|object $value)
33+
Returns the BSON representation of a PHP value */
34+
PHP_FUNCTION(MongoDB_BSON_fromPHP)
35+
{
36+
zval *data;
37+
bson_t *bson;
38+
39+
SUPPRESS_UNUSED_WARNING(return_value_ptr) SUPPRESS_UNUSED_WARNING(this_ptr) SUPPRESS_UNUSED_WARNING(return_value_used) /* We don't use these */
40+
41+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "A", &data) == FAILURE) {
42+
return;
43+
}
44+
45+
bson = bson_new();
46+
php_phongo_zval_to_bson(data, PHONGO_BSON_NONE, bson, NULL TSRMLS_CC);
47+
48+
PHONGO_RETVAL_STRINGL((const char *) bson_get_data(bson), bson->len);
49+
bson_destroy(bson);
50+
} /* }}} */
51+
52+
/* {{{ proto array|object MongoDB\BSON\toPHP(string $bson [, array $typemap = array()])
53+
Returns the PHP representation of a BSON value, optionally converting it into a custom class */
54+
PHP_FUNCTION(MongoDB_BSON_toPHP)
55+
{
56+
char *data;
57+
phongo_zpp_char_len data_len;
58+
zval *typemap = NULL;
59+
php_phongo_bson_state state = PHONGO_BSON_STATE_INITIALIZER;
60+
61+
SUPPRESS_UNUSED_WARNING(return_value_ptr) SUPPRESS_UNUSED_WARNING(this_ptr) SUPPRESS_UNUSED_WARNING(return_value_used) /* We don't use these */
62+
63+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a!", &data, &data_len, &typemap) == FAILURE) {
64+
return;
65+
}
66+
67+
if (!php_phongo_bson_typemap_to_state(typemap, &state.map TSRMLS_CC)) {
68+
return;
69+
}
70+
71+
if (!php_phongo_bson_to_zval_ex((const unsigned char *)data, data_len, &state)) {
72+
zval_ptr_dtor(&state.zchild);
73+
RETURN_NULL();
74+
}
75+
76+
#if PHP_VERSION_ID >= 70000
77+
RETURN_ZVAL(&state.zchild, 0, 1);
78+
#else
79+
RETURN_ZVAL(state.zchild, 0, 1);
80+
#endif
81+
} /* }}} */
82+
83+
/* {{{ proto string MongoDB\BSON\fromJSON(string $json)
84+
Returns the BSON representation of a JSON value */
85+
PHP_FUNCTION(MongoDB_BSON_fromJSON)
86+
{
87+
char *json;
88+
phongo_zpp_char_len json_len;
89+
bson_t bson = BSON_INITIALIZER;
90+
bson_error_t error;
91+
92+
SUPPRESS_UNUSED_WARNING(return_value_ptr) SUPPRESS_UNUSED_WARNING(this_ptr) SUPPRESS_UNUSED_WARNING(return_value_used) /* We don't use these */
93+
94+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &json, &json_len) == FAILURE) {
95+
return;
96+
}
97+
98+
if (bson_init_from_json(&bson, (const char *)json, json_len, &error)) {
99+
PHONGO_RETVAL_STRINGL((const char *) bson_get_data(&bson), bson.len);
100+
bson_destroy(&bson);
101+
} else {
102+
phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE TSRMLS_CC, "%s", error.domain == BSON_ERROR_JSON ? error.message : "Error parsing JSON");
103+
}
104+
} /* }}} */
105+
106+
static void phongo_bson_to_json(INTERNAL_FUNCTION_PARAMETERS, php_phongo_json_mode_t mode)
107+
{
108+
char *data;
109+
phongo_zpp_char_len data_len;
110+
const bson_t *bson;
111+
bool eof = false;
112+
bson_reader_t *reader;
113+
char *json = NULL;
114+
size_t json_len;
115+
116+
SUPPRESS_UNUSED_WARNING(return_value_ptr) SUPPRESS_UNUSED_WARNING(this_ptr) SUPPRESS_UNUSED_WARNING(return_value_used) /* We don't use these */
117+
118+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len) == FAILURE) {
119+
return;
120+
}
121+
122+
reader = bson_reader_new_from_data((const unsigned char *)data, data_len);
123+
bson = bson_reader_read(reader, NULL);
124+
125+
if (!bson) {
126+
phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE TSRMLS_CC, "Could not read document from BSON reader");
127+
bson_reader_destroy(reader);
128+
return;
129+
}
130+
131+
if (mode == PHONGO_JSON_MODE_LEGACY) {
132+
json = bson_as_json(bson, &json_len);
133+
} else if (mode == PHONGO_JSON_MODE_CANONICAL) {
134+
json = bson_as_canonical_json(bson, &json_len);
135+
} else if (mode == PHONGO_JSON_MODE_RELAXED) {
136+
json = bson_as_relaxed_json(bson, &json_len);
137+
}
138+
139+
if (!json) {
140+
phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE TSRMLS_CC, "Could not convert BSON document to a JSON string");
141+
bson_reader_destroy(reader);
142+
return;
143+
}
144+
145+
PHONGO_RETVAL_STRINGL(json, json_len);
146+
bson_free(json);
147+
148+
if (bson_reader_read(reader, &eof) || !eof) {
149+
phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE TSRMLS_CC, "Reading document did not exhaust input buffer");
150+
}
151+
152+
bson_reader_destroy(reader);
153+
} /* }}} */
154+
155+
/* {{{ proto string MongoDB\BSON\toJSON(string $bson)
156+
Returns the legacy extended JSON representation of a BSON value */
157+
PHP_FUNCTION(MongoDB_BSON_toJSON)
158+
{
159+
phongo_bson_to_json(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHONGO_JSON_MODE_LEGACY);
160+
} /* }}} */
161+
162+
/* {{{ proto string MongoDB\BSON\toCanonicalJSON(string $bson)
163+
Returns the canonical JSON representation of a BSON value */
164+
PHP_FUNCTION(MongoDB_BSON_toCanonicalJSON)
165+
{
166+
phongo_bson_to_json(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHONGO_JSON_MODE_CANONICAL);
167+
} /* }}} */
168+
169+
/* {{{ proto string MongoDB\BSON\toRelaxedJSON(string $bson)
170+
Returns the relaxed JSON representation of a BSON value */
171+
PHP_FUNCTION(MongoDB_BSON_toRelaxedJSON)
172+
{
173+
phongo_bson_to_json(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHONGO_JSON_MODE_RELAXED);
174+
} /* }}} */
175+
176+
/*
177+
* Local variables:
178+
* tab-width: 4
179+
* c-basic-offset: 4
180+
* End:
181+
* vim600: noet sw=4 ts=4 fdm=marker
182+
* vim<600: noet sw=4 ts=4
183+
*/

src/BSON/functions.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright 2014-2017 MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef PHONGO_BSON_FUNCTIONS_H
18+
#define PHONGO_BSON_FUNCTIONS_H
19+
20+
#include <php.h>
21+
22+
PHP_FUNCTION(MongoDB_BSON_fromPHP);
23+
PHP_FUNCTION(MongoDB_BSON_toPHP);
24+
25+
PHP_FUNCTION(MongoDB_BSON_fromJSON);
26+
PHP_FUNCTION(MongoDB_BSON_toJSON);
27+
PHP_FUNCTION(MongoDB_BSON_toCanonicalJSON);
28+
PHP_FUNCTION(MongoDB_BSON_toRelaxedJSON);
29+
30+
#endif /* PHONGO_BSON_FUNCTIONS_H */
31+
32+
33+
/*
34+
* Local variables:
35+
* tab-width: 4
36+
* c-basic-offset: 4
37+
* End:
38+
* vim600: noet sw=4 ts=4 fdm=marker
39+
* vim<600: noet sw=4 ts=4
40+
*/

0 commit comments

Comments
 (0)