From 8f200b3905fa80a810c769d8e660a64cf1a1be0e Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Mon, 7 Apr 2014 00:53:46 +0200 Subject: [PATCH] Call __set if JS accesses private/protected property --- tests/property_visibility-set.phpt | 5 +++ tests/property_visibility__set.phpt | 67 +++++++++++++++++++++++++++++ v8js_convert.cc | 36 ++++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 tests/property_visibility__set.phpt diff --git a/tests/property_visibility-set.phpt b/tests/property_visibility-set.phpt index 5b571c7..99a151f 100644 --- a/tests/property_visibility-set.phpt +++ b/tests/property_visibility-set.phpt @@ -14,6 +14,7 @@ class Foo { var_dump($this->privBar); var_dump($this->protBar); var_dump($this->pubBar); + var_dump($this->unknownBar); } } @@ -25,10 +26,12 @@ $script = <<foo->dump(); string(6) "jsPriv" string(6) "jsProt" string(5) "jsPub" +string(9) "jsUnknown" string(7) "privBar" string(7) "protBar" string(5) "jsPub" +string(9) "jsUnknown" ===EOF=== diff --git a/tests/property_visibility__set.phpt b/tests/property_visibility__set.phpt new file mode 100644 index 0000000..d698b3c --- /dev/null +++ b/tests/property_visibility__set.phpt @@ -0,0 +1,67 @@ +--TEST-- +Test V8::executeString() : Property visibility __set +--SKIPIF-- + +--FILE-- +privBar); + var_dump($this->protBar); + var_dump($this->pubBar); + var_dump(isset($this->unknownBar)); + var_dump(isset($this->phpBar)); + } +} + +$js = new V8Js(); + +$js->foo = new Foo(); +$js->foo->protBar = 'piet'; +$js->foo->phpBar = 'phpValue'; + +$script = <<executeString($script); +$js->foo->dump(); +?> +===EOF=== +--EXPECT-- +protBar <- piet +phpBar <- phpValue +privBar <- jsPriv +protBar <- jsProt +unknownBar <- jsUnknown +NULL +NULL +string(5) "jsPub" +NULL +NULL +string(7) "privBar" +string(7) "protBar" +string(5) "jsPub" +bool(false) +bool(false) +===EOF=== diff --git a/v8js_convert.cc b/v8js_convert.cc index 5bf3e4c..356317b 100644 --- a/v8js_convert.cc +++ b/v8js_convert.cc @@ -670,6 +670,42 @@ static inline v8::Local php_v8js_named_property_callback(v8::Localfunction_table, "__set", 6, (void**)&method_ptr) == SUCCESS + /* Allow only public methods */ + && ((method_ptr->common.fn_flags & ZEND_ACC_PUBLIC) != 0)) { + /* Okay, let's call __set. */ + zend_fcall_info fci; + + zval fmember; + ZVAL_STRING(&fmember, "__set", 0); + + zval *php_ret_value; + + 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_ret_value; + fci.param_count = 2; + + zval *zname_ptr = &zname; + + zval **params[2]; + fci.params = params; + fci.params[0] = &zname_ptr; + fci.params[1] = &php_value; + + zend_call_function(&fci, NULL TSRMLS_CC); + + ret_value = zval_to_v8js(php_ret_value, isolate TSRMLS_CC); + + /* We don't own the reference to php_ret_value... unless the + * returned refcount was 0, in which case the below code + * will free it. */ + zval_add_ref(&php_ret_value); + zval_ptr_dtor(&php_ret_value); + } } // if PHP wanted to hold on to this value, update_property would