summaryrefslogtreecommitdiff
path: root/lib/php
diff options
context:
space:
mode:
authorkufd <kosinski@ukr.net>2017-03-19 19:48:50 +0200
committerJames E. King, III <jking@apache.org>2017-03-30 16:42:11 -0400
commit1360270eb8e03402d48322514eaa58342e5b25d0 (patch)
tree01e53bce495ade0a3db3eef3b1f16669a2f7e4af /lib/php
parent7470995ce4bb480a86beaf1d8babce95c6f4b8c7 (diff)
downloadthrift-1360270eb8e03402d48322514eaa58342e5b25d0.tar.gz
THRIFT-4126: implement required fields validation in php extension when validate compiler option is enabled
Client: php This closes #1215
Diffstat (limited to 'lib/php')
-rw-r--r--lib/php/src/ext/thrift_protocol/php_thrift_protocol.cpp44
-rw-r--r--lib/php/src/ext/thrift_protocol/php_thrift_protocol7.cpp42
2 files changed, 85 insertions, 1 deletions
diff --git a/lib/php/src/ext/thrift_protocol/php_thrift_protocol.cpp b/lib/php/src/ext/thrift_protocol/php_thrift_protocol.cpp
index f9b3ad76e..4c9062e80 100644
--- a/lib/php/src/ext/thrift_protocol/php_thrift_protocol.cpp
+++ b/lib/php/src/ext/thrift_protocol/php_thrift_protocol.cpp
@@ -728,6 +728,42 @@ inline bool ttypes_are_compatible(int8_t t1, int8_t t2) {
return ((t1 == t2) || (ttype_is_int(t1) && ttype_is_int(t2)));
}
+//is used to validate objects before serialization and after deserialization. For now, only required fields are validated.
+static
+void validate_thrift_object(zval* object) {
+
+ HashPosition key_ptr;
+ zval** val_ptr;
+
+ TSRMLS_FETCH();
+ zend_class_entry* object_class_entry = zend_get_class_entry(object TSRMLS_CC);
+ HashTable* spec = Z_ARRVAL_P(zend_read_static_property(object_class_entry, "_TSPEC", 6, false TSRMLS_CC));
+
+ for (zend_hash_internal_pointer_reset_ex(spec, &key_ptr); zend_hash_get_current_data_ex(spec, (void**)&val_ptr, &key_ptr) == SUCCESS; zend_hash_move_forward_ex(spec, &key_ptr)) {
+ ulong fieldno;
+ if (zend_hash_get_current_key_ex(spec, NULL, NULL, &fieldno, 0, &key_ptr) != HASH_KEY_IS_LONG) {
+ throw_tprotocolexception("Bad keytype in TSPEC (expected 'long')", INVALID_DATA);
+ return;
+ }
+ HashTable* fieldspec = Z_ARRVAL_PP(val_ptr);
+
+ // field name
+ zend_hash_find(fieldspec, "var", 4, (void**)&val_ptr);
+ char* varname = Z_STRVAL_PP(val_ptr);
+
+ zend_hash_find(fieldspec, "isRequired", 11, (void**)&val_ptr);
+ bool is_required = Z_BVAL_PP(val_ptr);
+
+ zval* prop = zend_read_property(object_class_entry, object, varname, strlen(varname), false TSRMLS_CC);
+
+ if (is_required && Z_TYPE_P(prop) == IS_NULL) {
+ char errbuf[128];
+ snprintf(errbuf, 128, "Required field %s.%s is unset!", object_class_entry->name, varname);
+ throw_tprotocolexception(errbuf, INVALID_DATA);
+ }
+ }
+}
+
void binary_deserialize_spec(zval* zthis, PHPInputTransport& transport, HashTable* spec) {
// SET and LIST have 'elem' => array('type', [optional] 'class')
// MAP has 'val' => array('type', [optiona] 'class')
@@ -737,7 +773,10 @@ void binary_deserialize_spec(zval* zthis, PHPInputTransport& transport, HashTabl
zval** val_ptr = NULL;
int8_t ttype = transport.readI8();
- if (ttype == T_STOP) return;
+ if (ttype == T_STOP) {
+ validate_thrift_object(zthis);
+ return;
+ }
int16_t fieldno = transport.readI16();
if (zend_hash_index_find(spec, fieldno, (void**)&val_ptr) == SUCCESS) {
HashTable* fieldspec = Z_ARRVAL_PP(val_ptr);
@@ -903,6 +942,9 @@ void binary_serialize(int8_t thrift_typeID, PHPOutputTransport& transport, zval*
void binary_serialize_spec(zval* zthis, PHPOutputTransport& transport, HashTable* spec) {
+
+ validate_thrift_object(zthis);
+
HashPosition key_ptr;
zval** val_ptr;
diff --git a/lib/php/src/ext/thrift_protocol/php_thrift_protocol7.cpp b/lib/php/src/ext/thrift_protocol/php_thrift_protocol7.cpp
index da5b3de99..6d8b76fe9 100644
--- a/lib/php/src/ext/thrift_protocol/php_thrift_protocol7.cpp
+++ b/lib/php/src/ext/thrift_protocol/php_thrift_protocol7.cpp
@@ -849,6 +849,44 @@ bool ttypes_are_compatible(int8_t t1, int8_t t2) {
return ((t1 == t2) || (ttype_is_int(t1) && ttype_is_int(t2)));
}
+//is used to validate objects before serialization and after deserialization. For now, only required fields are validated.
+static
+void validate_thrift_object(zval* object) {
+ zend_class_entry* object_class_entry = Z_OBJCE_P(object);
+ zval* is_validate = zend_read_static_property(object_class_entry, "isValidate", sizeof("isValidate")-1, false);
+ zval* spec = zend_read_static_property(object_class_entry, "_TSPEC", sizeof("_TSPEC")-1, false);
+ HashPosition key_ptr;
+ zval* val_ptr;
+
+ if (Z_TYPE_INFO_P(is_validate) == IS_TRUE) {
+ for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(spec), &key_ptr);
+ (val_ptr = zend_hash_get_current_data_ex(Z_ARRVAL_P(spec), &key_ptr)) != nullptr;
+ zend_hash_move_forward_ex(Z_ARRVAL_P(spec), &key_ptr)) {
+
+ zend_ulong fieldno;
+ if (zend_hash_get_current_key_ex(Z_ARRVAL_P(spec), nullptr, &fieldno, &key_ptr) != HASH_KEY_IS_LONG) {
+ throw_tprotocolexception("Bad keytype in TSPEC (expected 'long')", INVALID_DATA);
+ return;
+ }
+ HashTable* fieldspec = Z_ARRVAL_P(val_ptr);
+
+ // field name
+ zval* zvarname = zend_hash_str_find(fieldspec, "var", sizeof("var")-1);
+ char* varname = Z_STRVAL_P(zvarname);
+
+ zval* is_required = zend_hash_str_find(fieldspec, "isRequired", sizeof("isRequired")-1);
+ zval rv;
+ zval* prop = zend_read_property(object_class_entry, object, varname, strlen(varname), false, &rv);
+
+ if (Z_TYPE_INFO_P(is_required) == IS_TRUE && Z_TYPE_P(prop) == IS_NULL) {
+ char errbuf[128];
+ snprintf(errbuf, 128, "Required field %s.%s is unset!", ZSTR_VAL(object_class_entry->name), varname);
+ throw_tprotocolexception(errbuf, INVALID_DATA);
+ }
+ }
+ }
+}
+
static
void binary_deserialize_spec(zval* zthis, PHPInputTransport& transport, HashTable* spec) {
// SET and LIST have 'elem' => array('type', [optional] 'class')
@@ -857,6 +895,7 @@ void binary_deserialize_spec(zval* zthis, PHPInputTransport& transport, HashTabl
while (true) {
int8_t ttype = transport.readI8();
if (ttype == T_STOP) {
+ validate_thrift_object(zthis);
return;
}
@@ -892,6 +931,9 @@ void binary_deserialize_spec(zval* zthis, PHPInputTransport& transport, HashTabl
static
void binary_serialize_spec(zval* zthis, PHPOutputTransport& transport, HashTable* spec) {
+
+ validate_thrift_object(zthis);
+
HashPosition key_ptr;
zval* val_ptr;