]> granicus.if.org Git - php/commitdiff
Fixed bug #29210 (Function: is_callable - no support for private and protected classes).
authorDmitry Stogov <dmitry@php.net>
Wed, 27 Apr 2005 15:44:06 +0000 (15:44 +0000)
committerDmitry Stogov <dmitry@php.net>
Wed, 27 Apr 2005 15:44:06 +0000 (15:44 +0000)
NEWS
Zend/tests/bug29210.phpt [new file with mode: 0644]
Zend/zend_API.c
Zend/zend_API.h
Zend/zend_object_handlers.c
Zend/zend_object_handlers.h
ext/standard/basic_functions.c

diff --git a/NEWS b/NEWS
index f50e5a28e6c1805ae86570cc19fca7815ae271b0..ba504c97b0d06b4b2c64d8a9d795a905fbd2fb34 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -60,6 +60,8 @@ PHP                                                                        NEWS
   (Dmitry)
 - Fixed bug #29944 (Function defined in switch, crashes). (Dmitry)
 - Fixed bug #29583 (crash when echoing a COM object). (M.Sisolak, Wez)
+- Fixed bug #29210 (Function: is_callable - no support for private and
+  protected classes). (Dmitry)
 - Fixed bug #29104 (Function declaration in method doesn't work). (Dmitry)
 - Fixed bug #28839 (SIGSEGV in interactive mode (php -a)).
   (kameshj at fastmail dot fm)
diff --git a/Zend/tests/bug29210.phpt b/Zend/tests/bug29210.phpt
new file mode 100644 (file)
index 0000000..2946854
--- /dev/null
@@ -0,0 +1,104 @@
+--TEST--
+Bug #29210 Function: is_callable - no support for private and protected classes 
+--FILE--
+<?php
+class test_class {
+   private function test_func1() {
+        echo "test_func1\n";
+   }
+   protected function test_func2() {
+        echo "test_func2\n";
+   }
+   static private function test_func3() {
+        echo "test_func3\n";
+   }
+   static protected function test_func4() {
+        echo "test_func4\n";
+   }
+   function test() {
+     if (is_callable(array($this,'test_func1'))) {
+            $this->test_func1();
+     } else {
+       echo "test_func1 isn't callable from inside\n";
+     }
+     if (is_callable(array($this,'test_func2'))) {
+            $this->test_func2();
+     } else {
+       echo "test_func2 isn't callable from inside\n";
+     }
+     if (is_callable(array('test_class','test_func3'))) {
+            test_class::test_func3();
+     } else {
+       echo "test_func3 isn't callable from inside\n";
+     }
+     if (is_callable(array('test_class','test_func4'))) {
+            test_class::test_func4();
+     } else {
+       echo "test_func4 isn't callable from inside\n";
+     }
+   }
+}
+
+class foo extends test_class {
+   function test() {
+     if (is_callable(array($this,'test_func1'))) {
+            $this->test_func1();
+     } else {
+       echo "test_func1 isn't callable from child\n";
+     }
+     if (is_callable(array($this,'test_func2'))) {
+            $this->test_func2();
+     } else {
+       echo "test_func2 isn't callable from child\n";
+     }
+     if (is_callable(array('test_class','test_func3'))) {
+            test_class::test_func3();
+     } else {
+       echo "test_func3 isn't callable from child\n";
+     }
+     if (is_callable(array('test_class','test_func4'))) {
+            test_class::test_func4();
+     } else {
+       echo "test_func4 isn't callable from child\n";
+     }
+   }
+}
+
+$object = new test_class;
+$object->test();
+if (is_callable(array($object,'test_func1'))) {
+       $object->test_func1();
+} else {
+  echo "test_func1 isn't callable from outside\n";
+}
+if (is_callable(array($object,'test_func2'))) {
+       $object->test_func2();
+} else {
+  echo "test_func2 isn't callable from outside\n";
+}
+if (is_callable(array('test_class','test_func3'))) {
+  test_class::test_func3();
+} else {
+  echo "test_func3 isn't callable from outside\n";
+}
+if (is_callable(array('test_class','test_func4'))) {
+  test_class::test_func4();
+} else {
+  echo "test_func4 isn't callable from outside\n";
+}
+$object = new foo();
+$object->test();
+?>
+--EXPECT--
+test_func1
+test_func2
+test_func3
+test_func4
+test_func1 isn't callable from outside
+test_func2 isn't callable from outside
+test_func3 isn't callable from outside
+test_func4 isn't callable from outside
+test_func1 isn't callable from child
+test_func2
+test_func3 isn't callable from child
+test_func4
index 24bf8473c5b037aa9c7aa5d8fb9cdbfc25c538a6..72666cf03ab0faf039f51937f252917c8c38962d 100644 (file)
@@ -1717,7 +1717,7 @@ ZEND_API int zend_disable_class(char *class_name, uint class_name_length TSRMLS_
        return 1;
 }
 
-ZEND_API zend_bool zend_is_callable(zval *callable, zend_bool syntax_only, char **callable_name)
+ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, char **callable_name)
 {
        char *lcname;
        zend_bool retval = 0;
@@ -1728,7 +1728,7 @@ ZEND_API zend_bool zend_is_callable(zval *callable, zend_bool syntax_only, char
                        if (callable_name) {
                                *callable_name = estrndup(Z_STRVAL_P(callable), Z_STRLEN_P(callable));
                        }
-                       if (syntax_only) {
+                       if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) {
                                return 1;
                        }
 
@@ -1765,7 +1765,7 @@ ZEND_API zend_bool zend_is_callable(zval *callable, zend_bool syntax_only, char
                                                        memcpy(ptr, Z_STRVAL_PP(method), Z_STRLEN_PP(method) + 1);
                                                }
 
-                                               if (syntax_only)
+                                               if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY)
                                                        return 1;
 
                                                lcname = zend_str_tolower_dup(Z_STRVAL_PP(obj), Z_STRLEN_PP(obj));
@@ -1794,14 +1794,28 @@ ZEND_API zend_bool zend_is_callable(zval *callable, zend_bool syntax_only, char
                                                        memcpy(ptr, Z_STRVAL_PP(method), Z_STRLEN_PP(method) + 1);
                                                }
 
-                                               if (syntax_only)
+                                               if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY)
                                                        return 1;
                                        }
 
                                        if (ce) {
+                                               zend_function *fbc;
+
                                                lcname = zend_str_tolower_dup(Z_STRVAL_PP(method), Z_STRLEN_PP(method));
-                                               if (zend_hash_exists(&ce->function_table, lcname, Z_STRLEN_PP(method)+1)) {
+                                               if (zend_hash_find(&ce->function_table, lcname, Z_STRLEN_PP(method)+1, (void **)&fbc) == SUCCESS) {
                                                        retval = 1;
+                                                       if ((check_flags & IS_CALLABLE_CHECK_NO_ACCESS) == 0) {
+                                                               if (fbc->op_array.fn_flags & ZEND_ACC_PRIVATE) {
+                                                                       if (!zend_check_private(fbc, (Z_TYPE_PP(obj) == IS_STRING)?EG(scope):(*obj)->value.obj.handlers->get_class_entry(*obj TSRMLS_CC), lcname, Z_STRLEN_PP(method) TSRMLS_CC)) {
+                                                                               retval = 0;
+                                                                       }
+                                                               } else if ((fbc->common.fn_flags & ZEND_ACC_PROTECTED)) {
+                                                                       if (!zend_check_protected(fbc->common.scope, EG(scope))) {
+                                                                               retval = 0;
+                                                                       }
+                                                               }
+                                                       }
+
                                                }
                                                /* check for __call too */
                                                if (retval == 0 && ce->__call != 0) {
index b8bb18b7c4889356621827d09d2f47bf68fb83b5..b73a4e7038bcdcc63510a0e30f6d076a62849181 100644 (file)
@@ -179,7 +179,11 @@ ZEND_API int zend_disable_function(char *function_name, uint function_name_lengt
 ZEND_API int zend_disable_class(char *class_name, uint class_name_length TSRMLS_DC);
 
 ZEND_API void zend_wrong_param_count(TSRMLS_D);
-ZEND_API zend_bool zend_is_callable(zval *callable, zend_bool syntax_only, char **callable_name);
+
+#define IS_CALLABLE_CHECK_SYNTAX_ONLY (1<<0)
+#define IS_CALLABLE_CHECK_NO_ACCESS   (1<<1)
+
+ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, char **callable_name);
 ZEND_API zend_bool zend_make_callable(zval *callable, char **callable_name TSRMLS_DC);
 ZEND_API char *zend_get_module_version(char *module_name);
 ZEND_API int zend_get_module_started(char *module_name);
index e7d618a5c04701e7cba9c0b6c960065c09191ea0..78ea73727338f58b7625c5f3586cac0eb8e78763 100644 (file)
@@ -612,7 +612,7 @@ ZEND_API void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS)
  * Returns the function address that should be called, or NULL
  * if no such function exists.
  */
-static inline zend_function *zend_check_private(zend_function *fbc, zend_class_entry *ce, int fn_flags, char *function_name_strval, int function_name_strlen TSRMLS_DC)
+static inline zend_function *zend_check_private_int(zend_function *fbc, zend_class_entry *ce, char *function_name_strval, int function_name_strlen TSRMLS_DC)
 {
        if (!ce) {
                return 0;
@@ -647,6 +647,11 @@ static inline zend_function *zend_check_private(zend_function *fbc, zend_class_e
 }
 
 
+ZEND_API int zend_check_private(zend_function *fbc, zend_class_entry *ce, char *function_name_strval, int function_name_strlen TSRMLS_DC)
+{
+       return zend_check_private_int(fbc, ce, function_name_strval, function_name_strlen TSRMLS_CC) != NULL;
+}
+
 /* Ensures that we're allowed to call a protected method.
  */
 ZEND_API int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope)
@@ -723,7 +728,7 @@ static union _zend_function *zend_std_get_method(zval *object, char *method_name
 
                /* Ensure that if we're calling a private function, we're allowed to do so.
                 */
-               updated_fbc = zend_check_private(fbc, object->value.obj.handlers->get_class_entry(object TSRMLS_CC), fbc->common.fn_flags, lc_method_name, method_len TSRMLS_CC);
+               updated_fbc = zend_check_private_int(fbc, object->value.obj.handlers->get_class_entry(object TSRMLS_CC), lc_method_name, method_len TSRMLS_CC);
                if (!updated_fbc) {
                        zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), method_name, EG(scope) ? EG(scope)->name : "");
                }
@@ -761,7 +766,7 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, char *f
 
                /* Ensure that if we're calling a private function, we're allowed to do so.
                 */
-               updated_fbc = zend_check_private(fbc, EG(scope), fbc->common.fn_flags, function_name_strval, function_name_strlen TSRMLS_CC); 
+               updated_fbc = zend_check_private_int(fbc, EG(scope), function_name_strval, function_name_strlen TSRMLS_CC); 
                if (!updated_fbc) {
                        zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), function_name_strval, EG(scope) ? EG(scope)->name : "");
                }
index 4c8d12eda38023ad2af30f92c23777709d14e339..f28fb9044bef75108443fc6463d7d483d08bf01e 100644 (file)
@@ -137,6 +137,8 @@ ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int ty
 #define IS_ZEND_STD_OBJECT(z)  ((z).type == IS_OBJECT && (Z_OBJ_HT((z))->get_class_entry != NULL))
 #define HAS_CLASS_ENTRY(z) (Z_OBJ_HT(z)->get_class_entry != NULL)
 
+ZEND_API int zend_check_private(union _zend_function *fbc, zend_class_entry *ce, char *function_name_strval, int function_name_strlen TSRMLS_DC);
+
 ZEND_API int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope);
 
 ZEND_API int zend_check_property_access(zend_object *zobj, char *prop_info_name TSRMLS_DC);
index 8c3b7a71e8b7efcc7fc8a4f4ff3fb8a598592730..5d824751fbc2445c2663046b94ad2a1f8472cfae 100644 (file)
@@ -1908,7 +1908,7 @@ PHP_FUNCTION(call_user_func)
                convert_to_string_ex(params[0]);
        }
 
-       if (!zend_is_callable(*params[0], 0, &name)) {
+       if (!zend_is_callable(*params[0], IS_CALLABLE_CHECK_NO_ACCESS, &name)) {
                php_error_docref1(NULL TSRMLS_CC, name, E_WARNING, "First argument is expected to be a valid callback");
                efree(name);
                efree(params);
@@ -1963,7 +1963,7 @@ PHP_FUNCTION(call_user_func_array)
                convert_to_string_ex(func);
        }
 
-       if (!zend_is_callable(*func, 0, &name)) {
+       if (!zend_is_callable(*func, IS_CALLABLE_CHECK_NO_ACCESS, &name)) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "First argument is expected to be a valid callback, '%s' was given", name);
                efree(name);
                RETURN_NULL();