From 170b1ff94c275a7dee949f04e4055b8a55c45146 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Sun, 6 Apr 2014 20:04:48 +0200 Subject: [PATCH] Handle property visibility and __get, refs #79 Protected and private properties should not be available to JS context. Instead call __get function, if the property is not accessible. --- tests/property_visibility.phpt | 33 ++++++++++++++++++ tests/property_visibility__get.phpt | 44 ++++++++++++++++++++++++ v8js_convert.cc | 53 ++++++++++++++++++++++++----- 3 files changed, 122 insertions(+), 8 deletions(-) create mode 100644 tests/property_visibility.phpt create mode 100644 tests/property_visibility__get.phpt diff --git a/tests/property_visibility.phpt b/tests/property_visibility.phpt new file mode 100644 index 0000000..5febdba --- /dev/null +++ b/tests/property_visibility.phpt @@ -0,0 +1,33 @@ +--TEST-- +Test V8::executeString() : Property visibility +--SKIPIF-- + +--FILE-- +foo = new Foo(); + +$script = <<executeString($script); +?> +===EOF=== +--EXPECT-- +NULL +NULL +string(6) "pubBar" +===EOF=== diff --git a/tests/property_visibility__get.phpt b/tests/property_visibility__get.phpt new file mode 100644 index 0000000..a8790ef --- /dev/null +++ b/tests/property_visibility__get.phpt @@ -0,0 +1,44 @@ +--TEST-- +Test V8::executeString() : Property visibility __get +--SKIPIF-- + +--FILE-- +foo = new Foo(); + +$script = <<executeString($script); +?> +===EOF=== +--EXPECT-- +string(10) "unknownBar" +int(42) +string(7) "privBar" +int(42) +string(7) "protBar" +int(42) +string(6) "pubBar" +===EOF=== diff --git a/v8js_convert.cc b/v8js_convert.cc index 4db7eef..e1eddc6 100644 --- a/v8js_convert.cc +++ b/v8js_convert.cc @@ -604,15 +604,52 @@ static inline v8::Local php_v8js_named_property_callback(v8::Local(); - } else { - // wrap it + zval zname; + ZVAL_STRINGL(&zname, name, name_len, 0); + zend_property_info *property_info = zend_get_property_info(ce, &zname, 1 TSRMLS_CC); + + if(property_info && property_info->flags & ZEND_ACC_PUBLIC) { + php_value = zend_read_property(NULL, object, V8JS_CONST name, name_len, true TSRMLS_CC); + // special case uninitialized_zval_ptr and return an empty value + // (indicating that we don't intercept this property) if the + // property doesn't exist. + if (php_value == EG(uninitialized_zval_ptr)) { + ret_value = v8::Handle(); + } else { + // wrap it + ret_value = zval_to_v8js(php_value, isolate TSRMLS_CC); + /* We don't own the reference to php_value... unless the + * returned refcount was 0, in which case the below code + * will free it. */ + zval_add_ref(&php_value); + zval_ptr_dtor(&php_value); + } + } + else if (zend_hash_find(&ce->function_table, "__get", 6, (void**)&method_ptr) == SUCCESS + /* Allow only public methods */ + && ((method_ptr->common.fn_flags & ZEND_ACC_PUBLIC) != 0)) { + /* Okay, let's call __get. */ + zend_fcall_info fci; + + zval fmember; + ZVAL_STRING(&fmember, "__get", 0); + + fci.size = sizeof(fci); + fci.function_table = &ce->function_table; + fci.function_name = &fmember; + fci.symbol_table = NULL; + fci.object_ptr = object; + fci.retval_ptr_ptr = &php_value; + fci.param_count = 1; + + zval *zname_ptr = &zname; + zval **zname_ptr_ptr = &zname_ptr; + fci.params = &zname_ptr_ptr; + + zend_call_function(&fci, NULL TSRMLS_CC); + ret_value = zval_to_v8js(php_value, isolate TSRMLS_CC); + /* We don't own the reference to php_value... unless the * returned refcount was 0, in which case the below code * will free it. */