Przeglądaj źródła

Call __set if JS accesses private/protected property

Stefan Siegl 11 lat temu
rodzic
commit
8f200b3905

+ 5 - 0
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 = <<<END
 PHP.foo.privBar = 'jsPriv';
 PHP.foo.protBar = 'jsProt';
 PHP.foo.pubBar = 'jsPub';
+PHP.foo.unknownBar = 'jsUnknown';
 
 var_dump(PHP.foo.privBar);
 var_dump(PHP.foo.protBar);
 var_dump(PHP.foo.pubBar);
+var_dump(PHP.foo.unknownBar);
 
 END;
 
@@ -40,7 +43,9 @@ $js->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===

+ 67 - 0
tests/property_visibility__set.phpt

@@ -0,0 +1,67 @@
+--TEST--
+Test V8::executeString() : Property visibility __set
+--SKIPIF--
+<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
+--FILE--
+<?php
+
+class Foo {
+	private $privBar = "privBar";
+	protected $protBar = "protBar";
+	public $pubBar = "pubBar";
+
+	public function __set($name, $value) {
+		echo "$name <- $value\n";
+	}
+
+	public function dump() {
+		var_dump($this->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 = <<<END
+
+PHP.foo.privBar = 'jsPriv';
+PHP.foo.protBar = 'jsProt';
+PHP.foo.pubBar = 'jsPub';
+PHP.foo.unknownBar = 'jsUnknown';
+
+var_dump(PHP.foo.privBar);
+var_dump(PHP.foo.protBar);
+var_dump(PHP.foo.pubBar);
+var_dump(PHP.foo.unknownBar);
+var_dump(PHP.foo.phpBar);
+
+END;
+
+$js->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===

+ 36 - 0
v8js_convert.cc

@@ -670,6 +670,42 @@ static inline v8::Local<v8::Value> php_v8js_named_property_callback(v8::Local<v8
 					zend_update_property(scope, object, V8JS_CONST name, name_len, php_value TSRMLS_CC);
 					ret_value = set_value;
 				}
+				else if (zend_hash_find(&ce->function_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