Hello.

After a short bout of hair-pulling, I have discovered the source (in the
Zend engine) of a recent problem, and have fixed it.

BACKGROUND:
As I have mentioned previously on this list, I am developing a complex
PHP extension, which among many other things creates its own PHP
classes, and when these classes are instantiated, I manually call the
class constructor (as one must) from my C code.

I am creating the extension from existing C++ and Java versions of the
same system, so I am trying to maintain things as much as possible,
including names (including capitalization) of classes and functions
(although I am prefixing them all with "eo_" to avoid potential
conflicts with functions and classes from other PHP extensions).

Thus, I have classes such as "eo_list", "eo_table" and "eo_NVList".  

THE SYMPTOM:
I had no trouble instantiating and calling the constructors for the
first two classes, but when I tried to do it for eo_NVList,
call_user_function_ex() was returning FAILURE, which I discovered can
occur for one of seven reasons.

I tracked down the problem to a failure of zend_hash_find() to lookup
the function.  Using zend_hash_display() I was able to verify that the
eo_NVList constructor was indeed contained in the function table for the
eo_NVList class.

THE PROBLEM:
call_user_function_ex() is converting the requested function name to
lower case (at zend_execute_API.c:463) before performing the
zend_hash_find(), but zend_register_functions() (in zend_API.c) does NOT
convert the function names to lower case before storing them in the
function table--so call_user_function_ex() was searching for a function
called "eo_nvlist" and could never find "eo_NVList"!

Class lookups worked fine of course, because object_init_ex() takes a
pointer to the class entry rather than a name.

Additionally, zend_register_internal_class() (also in zend_API.c)
converts all class names to lower case, and execute() (in
zend_execute.c) does the same when looking up a class to instantiate it
from a script.

I haven't looked into script-driven function registration and execution,
but presumably case-insensitivity is properly supported there, or I'm
sure you would have heard of it long ago!

MY SOLUTION:
I present the following little patch for your approval.

I apologize that it is done against 4.3.1 rather than the latest CVS but
I do not have time to deal with CVS at this time, as my project is
already behind schedule and of course I need to work with a stable
engine.  If zend_API.c has changed since the 4.3.1 release, it should be
trivial to change these few lines of code (yes, I'm sure they all say
that!). =)

I didn't find any patch submission guidlines in a quick web search; I'm
afraid you'll have to change the file/pathnames in the first lines.  If
you don't want to deal with that, point me to the guidelines and I will
resubmit the patch.  For now I will get back to work.

Respectfully,
Eric Lambart

--- Zend/OLD_zend_API.c Wed Oct  9 07:17:52 2002
+++ Zend/zend_API.c     Fri Mar  7 13:10:38 2003
@@ -1039,6 +1039,12 @@
        internal_function->type = ZEND_INTERNAL_FUNCTION;
        
        while (ptr->fname) {
+    /* store all function names in lower case so they will always be found by
+     * call_user_function_ex() */
+    size_t fname_len = strlen(ptr->fname);
+    char *lowercase_name = zend_strndup(ptr->fname, fname_len);
+    zend_str_tolower(lowercase_name, fname_len);
+
                internal_function->handler = ptr->handler;
                internal_function->arg_types = ptr->func_arg_types;
                internal_function->function_name = ptr->fname;
@@ -1047,7 +1053,7 @@
                        zend_unregister_functions(functions, count, 
target_function_table TSRMLS_CC);
                        return FAILURE;
                }
-               if (zend_hash_add(target_function_table, ptr->fname, 
strlen(ptr->fname)+1, &function, sizeof(zend_function), NULL) == FAILURE) {
+               if (zend_hash_add(target_function_table, lowercase_name, fname_len+1, 
&function, sizeof(zend_function), NULL) == FAILURE) {
                        unload=1;
                        break;
                }



-- 
PHP Development Mailing List <http://www.php.net/>
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to