cvs: php-src /ext/xmldbx CREDITS config.m4 php_xmldbx.h sessionxml.php xmldbx.c xmldbx.h xmldbx.php

From: Date: Sat, 28 Jan 2006 02:29:55 +0000
Subject: cvs: php-src /ext/xmldbx CREDITS config.m4 php_xmldbx.h sessionxml.php xmldbx.c xmldbx.h xmldbx.php
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-36657@lists.php.net to get a copy of this message
mlwmohawk Sat Jan 28 02:29:55 2006 UTC Added files: /php-src/ext/xmldbx CREDITS config.m4 php_xmldbx.h sessionxml.php xmldbx.c xmldbx.h xmldbx.php Log: Added

http://cvs.php.net/viewcvs.cgi/php-src/ext/xmldbx/config.m4?view=markup&rev=1.1 Index: php-src/ext/xmldbx/config.m4 +++ php-src/ext/xmldbx/config.m4 dnl dnl $Id: config.m4,v 1.1 2006/01/28 02:29:54 mlwmohawk Exp $ dnl PHP_ARG_ENABLE(xmldbx,whether to enable XMLdbX support, [ --enable-xmldbx Enable XMLdbX support.]) if test "$PHP_XMLDBX" != "no"; then if test "$ext_shared" != "yes" && test "$enable_xml" = "no"; then AC_MSG_WARN(Activating XML) enable_xml=yes fi AC_DEFINE(HAVE_XMLDBX, 1, [ ]) PHP_NEW_EXTENSION(xmldbx, xmldbx.c, $ext_shared) fi http://cvs.php.net/viewcvs.cgi/php-src/ext/xmldbx/php_xmldbx.h?view=markup&rev=1.1 Index: php-src/ext/xmldbx/php_xmldbx.h +++ php-src/ext/xmldbx/php_xmldbx.h /* +----------------------------------------------------------------------+ | PHP Version 4 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2003 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 2.02 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available at through the world-wide-web at | | http://www.php.net/license/2_02.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Credits: Andrei Zmievski <andrei@php.net> (wddx) | | Author: Mark Woodward <markw@mohawksoft.com> | +----------------------------------------------------------------------+ */ /* $Id: php_xmldbx.h,v 1.1 2006/01/28 02:29:54 mlwmohawk Exp $ */ #ifndef PHP_XMLDBX_H #define PHP_XMLDBX_H #if HAVE_XMLDBX extern zend_module_entry xmldbx_module_entry; #define xmldbx_module_ptr &xmldbx_module_entry PHP_FUNCTION(xmldbx_serialize); PHP_FUNCTION(xmldbx_deserialize); int xmldbx_deserialize_xml(zval **zret, const char *value, int vallen); char *xmldbx_serialize_xml(char *name, zval **obj); #define XMLDBX_MOHAWK #else #define xmldbx_module_ptr NULL #endif /* HAVE_XMLDBX */ #define phpext_xmldbx_ptr xmldbx_module_ptr #endif /* !PHP_XMLDBX_H */ http://cvs.php.net/viewcvs.cgi/php-src/ext/xmldbx/sessionxml.php?view=markup&rev=1.1 Index: php-src/ext/xmldbx/sessionxml.php +++ php-src/ext/xmldbx/sessionxml.php <? # sessionxml.php # Test xmldbx session serializer # class MyClass { var $count; var $mybool; var $mystring; function print_vars() { print "count = " . $this->count . "<br>\n"; print "bybool = " . $this->mybool . "<br>\n"; print "mystring = " . $this->mystring . "<br>\n"; $this->count++; if($this->mybool == True) $this->mybool = False; else $this->mybool = True; $this->mystring = $this->mystring . "+"; } }; # Start sessions, this will set a cookie. session_start(); session_register("count"); session_register("setarray"); session_register("mycls"); session_register("myinit"); if(!$myinit) { $mycls = new MyClass(); $myinit = true; } $count++; if($count < 2) { $_SESSION['setarray'] = array(); $_SESSION['setarray']['time']=time(); $_SESSION['setarray']['name1'] = 'xml_test1'; $_SESSION['setarray']['name2'] = 'xml_test2'; $_SESSION['setarray']['name3'] = 'xml_test3'; $_SESSION['setarray']['name4'] = 'xml_test4'; $_SESSION['setarray']['name5'] = 'xml_test5'; $_SESSION['setarray']['name6'] = 'xml_test6'; $_SESSION['setarray']['name7'] = 'xml_test7'; } echo $_SESSION['setarray']['name1'] . "<br>\n"; echo $_SESSION['setarray']['name2'] . "<br>\n"; echo $_SESSION['setarray']['name3'] . "<br>\n"; echo $_SESSION['setarray']['name4'] . "<br>\n"; echo $_SESSION['setarray']['name5'] . "<br>\n"; echo $_SESSION['setarray']['name6'] . "<br>\n"; echo $_SESSION['setarray']['name7'] . "<br>\n"; $mycls->print_vars(); # Output some information. echo "sid: " . $sid . "<br>\n"; echo "Session Count: " . $count . "<br>\n"; ?> http://cvs.php.net/viewcvs.cgi/php-src/ext/xmldbx/xmldbx.c?view=markup&rev=1.1 Index: php-src/ext/xmldbx/xmldbx.c +++ php-src/ext/xmldbx/xmldbx.c /* +----------------------------------------------------------------------+ | XMLDBX 1.0 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2003 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 2.02 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available at through the world-wide-web at | | http://www.php.net/license/2_02.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Credits: Andrei Zmievski <andrei@php.net> (wddx) | | Author: Mark Woodward <markw@mohawksoft.com> | +----------------------------------------------------------------------+ */ /* XMLDBX is a virtually complete re-write of WDDX. The problem wddx tried to address, XML PHP session storage, is a valid one, only that wddx failed to provide much more than a theoretical proof that it could be done. I have to applaud Andrei for the work he did, writing a serializer must be a PITA if you do not deal with Zend on a day to day basis. I used wddx extensively as a reference while writing xmldbx. When all is said and done, the wddx code was not exactly what I needed. I have a very different coding style and found the original wddx code lacking some basic modularity. My needs were more extensive, first, the wddx module was too verbose. This was really a problem if you had large amounts of session information, most of the actual data storage was XML formatting. XMLDBX does a few things differently, it flatens types to a single XML tag, using attributes for meta data. Second, it uses the variable name as the tag, not the type. The type is added as an attribute. One thing that is done that is questionable is using a value ("v") attribute to convey the value. This is nothing more than a space saver, and can be altered by removeing the XMLDBX_COMPACT_VARS define value, this will force all data to be put between "begin" and "end" tags. Mark L. Woodward <markw@mohawksoft.com>, 2005 Documentation and new version can be found at: http://www.mohawksoft.org 1/19/2006 Add "REFERENCE" type to XML stream and it should be ignored by all but PHP I guess. It seems Squirrelmail uses self referencing data strutuctures for session information. My management of reference types is imperfect as it relys on a parent child relationship to multiple references of a single variable, parallel references are not found, although that could be done if I replace the stack paradigm with a list and keep track of each and every variable on serialize and deserialize. Yuck!! 1/26/2006 Finally got a grip on zval referencing crap, I had to add a total of 3 new attributes, REFCOUNT, ISREF, and REFERENCE. I Use the hex address of a zval as its reference id and send that out in XML. Each subsequent reference to the same value emits a REFERENCE type with the hex reference id. At the xml decoder stage, if a variable has a REFERENCE attribute, it is pushed on the zval stack and later searched when a REFERENCE type is encountered in the XML stream. */ /* $Id: xmldbx.c,v 1.1 2006/01/28 02:29:54 mlwmohawk Exp $ */ // Needed to compile on PHP #define XMLDBX_USING_PHP // Enable PHP callable functions #define HAS_PHP_XMLDBX_FUNCTIONS // Enable debugging messages // #define ERR_DEBUG_EXTRA // #define ERR_DEBUG // #define DUMP_DEBUG // #define EMBED_DEBUG // #define ZVAL_DEBUG #define LOG_BAD_PARSE #include "php.h" #include "php_xmldbx.h" #if !defined (HAVE_LIBEXPAT) && !defined(LIBXML_EXPAT_COMPAT) #ifndef PHP_EXPAT_COMPAT_H #include <expat.h> #endif #endif #if HAVE_XMLDBX #include "xmldbx.h" #define PHP_XML_INTERNAL #ifndef XmlParse_INCLUDED #include "ext/xml/php_xml.h" #endif #include "ext/standard/php_incomplete_class.h" #include "ext/standard/base64.h" #include "ext/standard/info.h" #include "ext/standard/php_smart_str.h" #include "ext/standard/html.h" #include "ext/standard/php_string.h" // #include "ext/standard/php_parsedate.h" // Forwards static int EnumArray(zval *obj, EnumArrayCallback fn, void *p1, void *p2); static void xmldbx_data_handler(void *user_data, const XML_Char *s, int len); static void xmldbx_start(XMLDBXBUF *xmlbuf); static void xmldbx_end(XMLDBXBUF *xmlbuf); static XMLDBXBUF *xmldbx_constructor(void); static void xmldbx_destructor(XMLDBXBUF *xmlbuf); static void xmldbx_serialize_var(XMLDBXBUF *xmlbuf, zval *var, char *name, int name_len TSRMLS_DC); static char * xmldbx_open_var(XMLDBXBUF *xmlbuf, int ntype, char *name, char *classname, int len, char *entra); static void xmldbx_close_var(XMLDBXBUF *xmlbuf, char *name); static int xmldbx_bad_name(char *src); static char *xmldbx_types[]={ XT_NULL, // 0 XT_LONG, // 1 XT_DOUBLE, // 2 XT_STRING, // 3 XT_ARRAY, // 4 XT_OBJECT, // 5 XT_BOOLEAN, // 6 XT_RESOURCE, // 7 XT_CONSTANT, // 8 XT_CONSTANT_ARRAY, // 9 XT_REFERENCE, // 10 XT_NAME, // 11 XT_IGNORE // 12 }; static char xmldbx_empty_string[]=""; #define ALLOCMEM(cb) emalloc(cb) #define PALLOCMEM(cb) pemalloc(cb,0) #define FREEMEM(p) efree(p); #define PFREEMEM(p) pefree(p,0); #define ZDTOR(z) zval_dtor(z) #define ZDTORP(z) zval_ptr_dtor(z) /* {{{ xmldbx_functions[] */ function_entry xmldbx_functions[] = { #ifdef HAS_PHP_XMLDBX_FUNCTIONS PHP_FE(xmldbx_serialize, NULL) PHP_FE(xmldbx_deserialize, NULL) #endif {NULL, NULL, NULL} }; /* }}} */ PHP_MINIT_FUNCTION(xmldbx); PHP_MINFO_FUNCTION(xmldbx); /* {{{ xmldbx_module_entry */ zend_module_entry xmldbx_module_entry = { STANDARD_MODULE_HEADER, "xmldbx", xmldbx_functions, PHP_MINIT(xmldbx), NULL, NULL, NULL, PHP_MINFO(xmldbx), NO_VERSION_YET, STANDARD_MODULE_PROPERTIES }; /* }}} */ /* {{{ dynamically loadable module stuff */ #ifdef COMPILE_DL_XMLDBX ZEND_GET_MODULE(xmldbx) #endif /* COMPILE_DL_XMLDBX */ /* }}} */ /* {{{ xmldbx_logf * Uses printf syntax to write to php_log_err * Must remain in ERR_DEBUG ifdef to ensure it * does not get compiled into release code */ static void xmldbx_logf(char *fmt, ...) { va_list arglist; static char buffer[4096]; va_start(arglist, fmt); vsnprintf(buffer, sizeof(buffer), fmt, arglist); va_end(arglist); php_log_err(buffer); } /* }}} */ /* {{{ xmldbx_append_strf * Writes to a string using printf syntax */ void xmldbx_append_strf(XMLDBXBUF *xmlbuf, char *fmt, ...) { va_list arglist; char buffer[XMLDBX_BUF_LEN]; va_start(arglist, fmt); vsnprintf(buffer, sizeof(buffer), fmt, arglist); va_end(arglist); smart_str_appends(&xmlbuf->str, buffer); } /* }}} */ /* {{{ xmldbx_zentry_init * Initialize the zval stack */ static int xmldbx_zentry_init(ZVAL_ENTRIES *pzentry) { pzentry->zvals = ALLOCMEM(sizeof(ZVAL_ENTRY) * XMLDBX_ZSTACK_SIZE); if(!pzentry->zvals){ return FAILURE; } else { pzentry->nzvals = 0; pzentry->maxzvals = XMLDBX_ZSTACK_SIZE; return SUCCESS; } } /* }}} */ /* {{{ xmldbx_zentry_destory * Destory the zval stack */ static int xmldbx_zentry_destroy(ZVAL_ENTRIES *pzentry) { int i; for(i=0; i < pzentry->nzvals; i++){ if(pzentry->zvals[i].name) FREEMEM(pzentry->zvals[i].name); } FREEMEM(pzentry->zvals); } /* }}} */ /* {{{ xmldbx_push_zval * Push zval onto zval stack */ static int xmldbx_push_zval(ZVAL_ENTRIES *pzentry, char *name, zval *obj) { if (pzentry->nzvals >= pzentry->maxzvals) { /* we need to allocate more memory */ int newmax = pzentry->maxzvals * 2; pzentry->zvals = (ZVAL_ENTRY *)erealloc(pzentry->zvals,(sizeof(ZVAL_ENTRY)* newmax)); if (!pzentry->zvals) { php_error(E_WARNING, "Did not allocate ZVAL stack"); return FAILURE; } else pzentry->maxzvals = newmax; } if(!name) name=""; #ifdef ZVAL_DEBUG xmldbx_logf("xmldbx_push_zval name:%s address:%X entry:%d refcount:%d is_ref:%d", name, obj, pzentry->nzvals, obj->refcount, obj->is_ref); #endif pzentry->zvals[pzentry->nzvals].name = estrdup(name); pzentry->zvals[pzentry->nzvals].obj = obj; pzentry->nzvals++; return SUCCESS; } /* }}} */ /* {{{ xmldbx_find_dupzval * Find a duplicate in the zval stack */ static int xmldbx_find_dupzval(ZVAL_ENTRIES *pzentry, char *name, zval *var) { int i; for(i=0; i < pzentry->nzvals; i++) { if(pzentry->zvals[i].obj == var){ #ifdef ZVAL_DEBUG xmldbx_logf("found duplicate %X, %s is_ref:%d, refcount:%d", var, name, var->is_ref, var->refcount); #endif return 1; } } return 0; } /* }}} */ /* {{{ xmldbx_stack_init * Initialize the XML decode stack */ static int xmldbx_stack_init(xmldbx_stack *stack) { int cb = sizeof(xmldbx_tag) * XMLDBX_STACK_SIZE; memset(stack, 0, sizeof(xmldbx_stack)); stack->tags = (xmldbx_tag *) ALLOCMEM(cb); xmldbx_zentry_init(&stack->zentry); if (!stack->tags) { return FAILURE; } else { memset(stack->tags, 0, cb); stack->max = XMLDBX_STACK_SIZE; stack->state = XPS_IDLE; return SUCCESS; } } /* }}} */ /* {{{ xmldbx_stack_set_return * Sets the return value in the decode stack */ static void xmldbx_stack_set_return(xmldbx_stack *stack, xmldbx_tag *tag) { ELOG_FUNC("xmldbx_stack_set_return"); stack->retval = tag->data; tag->data = NULL; // Make sure, no double deletes stack->state = XPS_DONE; } /* }}} */ /* {{{ xmldbx_stack_get_return * Returns the value stored in the decode stack */ static zval *xmldbx_stack_get_return(xmldbx_stack *stack) { return stack->retval; } /* }}} */ /* {{{ xmldbx_stack_push * Push a tag onto the decode stack */ static int xmldbx_stack_push(xmldbx_stack *stack, xmldbx_tag *tag) { ELOG_FUNC("xmldbx_stack_push"); #ifdef ERR_DEBUG_ENTRA if(tag->vname) ELOG(tag->vname); #endif if (stack->top >= stack->max) { /* we need to allocate more memory */ int newmax = stack->max+XMLDBX_STACK_SIZE; stack->tags = (xmldbx_tag *) erealloc(stack->tags,(sizeof(xmldbx_tag)* newmax)); if (!stack->tags) { return FAILURE; } else { stack->max = newmax; } } stack->top++; stack->tags[stack->top] = *tag; return stack->top; } /* }}} */ /* {{{ xmldbx_stack_pop * Pop a tag from the decode stack */ static int xmldbx_stack_pop(xmldbx_stack *stack, xmldbx_tag *tag) { ELOG_FUNC("xmldbx_stack_pop"); if(stack->top > 0) { if(tag) { *tag = stack->tags[stack->top]; // Avoid double deletes stack->tags[stack->top].data = NULL; stack->tags[stack->top].xname = NULL; stack->tags[stack->top].vname = NULL; } stack->top--; } return stack->top; } /* }}} */ /* {{{ xmldbx_stack_curr * Returns a pointer to the current stack entry */ static int xmldbx_stack_curr(xmldbx_stack *stack, xmldbx_tag **tag) { ELOG_FUNC("xmldbx_stack_curr"); if (stack->top > 0) { *tag = &stack->tags[stack->top]; return SUCCESS; } else { *tag = NULL; return FAILURE; } } /* }}} */ /* {{{ xmldbx_stack_is_empty * Return non-zero is the decode stack is empty */ static int xmldbx_stack_is_empty(xmldbx_stack *stack) { ELOG_FUNC("xmldbx_stack_is_empty"); if (stack->top == 0) { return 1; } else { return 0; } } /* }}} */ /* {{{ xmldbx_clear_tag * Clears a tag */ static void xmldbx_clear_tag(xmldbx_tag *tag) { if(tag->vname != tag->xname) { if(tag->vname) { FREEMEM(tag->vname); tag->vname = NULL; } } if(tag->xname) { FREEMEM(tag->xname); tag->xname = NULL; } } /* }}} */ /* {{{ xmldbx_stack_destroy * Clean up the decode stack */ static int xmldbx_stack_destroy(xmldbx_stack *stack) { ELOG_FUNC("xmldbx_stack_destroy"); register int i; if (stack->tags) { for (i = 1; i < stack->top; i++) { xmldbx_clear_tag(&stack->tags[i]); } FREEMEM(stack->tags); stack->tags=NULL; } xmldbx_zentry_destroy(&stack->zentry); return SUCCESS; } /* }}} */ /* {{{ xmldbx_find_attr * Returns the value of the XML attribute specified or NULL. */ static XML_Char * xmldbx_find_attr(XML_Char *attrib, const XML_Char **atts) { int i; ELOG_FUNC("xmldbx_find_attr"); for(i=0; atts[i]; i+=2) { if(!strcmp(attrib, atts[i])) { int ndx = i+1; if(atts[ndx] && strlen(atts[ndx])) return (XML_Char *)atts[ndx]; } } return NULL; } /* }}} */ /* {{{ xmldbx_log_string * Creates a file based on prefix, processid, and static count * and writes string to it. */ static xmldbx_log_string(char *prefix, const char *string) { static int n=0; char buffer[1024]; FILE *f; pid_t p = getpid(); sprintf(buffer, "/tmp/%s%d_%d.xml", prefix, p,n++); ELOG(buffer); f = fopen(buffer, "w+"); if(f) fwrite(string, strlen(string), 1, f); fclose(f); } /* }}} */ #include "ext/session/php_session.h" #if HAVE_PHP_SESSION /* {{{ PS_SERIALIZER_ENCODE_FUNC */ PS_SERIALIZER_ENCODE_FUNC(xmldbx) { XMLDBXBUF *xmlbuf=NULL; char *xname=NULL; PS_ENCODE_VARS; ELOG_FUNC("SERIALIZER_ENCODE_FUNC"); xmlbuf = xmldbx_constructor(); if (!xmlbuf) return FAILURE; xmldbx_start(xmlbuf); xname = xmldbx_open_var(xmlbuf, ST_OBJECT, XST_DATA, NULL, 0, NULL); PS_ENCODE_LOOP( xmldbx_serialize_var(xmlbuf, *struc, key, key_length TSRMLS_CC); ); xmldbx_close_var(xmlbuf,xname); xmldbx_end(xmlbuf); *newstr = estrndup(xmlbuf->str.c, xmlbuf->str.len); xmldbx_destructor(xmlbuf); #ifdef DUMP_DEBUG xmldbx_log_string("encode_", *newstr); #endif if (newlen) *newlen = strlen(*newstr); return SUCCESS; } /* }}} */ /* {{{ aeSetSessionVars(ArrayEnumStruct *ae) * Set the enumerated variables into the session array */ static int aeSetSessionVars(ArrayEnumStruct *ae) { zval *lent; char key[128]; int cbkey; ELOG("aeSetSessionVars"); #ifdef ERR_DEBUG assert(ae); #endif if(ae->ent && *ae->ent) { switch (ae->type) { case HASH_KEY_IS_LONG: E2LOG(key); E2LOG("HASH_KEY_IS_LONG"); cbkey = snprintf(key, sizeof(key),"%ld", ae->physndx); php_set_session_var(key, cbkey, *ae->ent, NULL TSRMLS_CC); PS_ADD_VAR(key); break; case HASH_KEY_IS_STRING: E2LOG("HASH_KEY_IS_STRING"); E2LOG(ae->key); php_set_session_var(ae->key, ae->keylen-1, *ae->ent, NULL TSRMLS_CC); PS_ADD_VAR(ae->key); break; #ifdef ERR_DEBUG_EXTRA default: E2LOG("Unknown type"); break; #endif } } return 1; } /* }}} */ /* {{{ PS_SERIALIZER_DECODE_FUNC */ PS_SERIALIZER_DECODE_FUNC(xmldbx) { zval *zret; int ret = FAILURE; ELOG_FUNC("SERIALIZER_DECODE_FUNC"); if (vallen <= 0) return SUCCESS; #ifdef DUMP_DEBUG xmldbx_log_string("decode_", val); #endif if ((ret = xmldbx_deserialize_xml(&zret,val,vallen)) == SUCCESS) { E2LOG("xmldbx_deserialize_xml == SUCCESS"); if(zret) EnumArray(zret, aeSetSessionVars, NULL, NULL); } return ret; } /* }}} */ #endif /* {{{ PHP_MINIT_FUNCTION */ static int xmldbx_modnum; PHP_MINIT_FUNCTION(xmldbx) { int i; ELOG_FUNC("PHP_MINIT_FUNCTION"); #if HAVE_PHP_SESSION E2LOG("Calling register_serializer"); i = php_session_register_serializer("xmldbx", PS_SERIALIZER_ENCODE_NAME(xmldbx), PS_SERIALIZER_DECODE_NAME(xmldbx)); #endif return SUCCESS; } /* }}} */ /* {{{ PHP_MINFO_FUNCTION */ PHP_MINFO_FUNCTION(xmldbx) { ELOG_FUNC("PHP_MINFO_FUNCTION"); php_info_print_table_start(); #if HAVE_PHP_SESSION E2LOG("HAVE_PHP_SESSION"); php_info_print_table_header(2, "XMLDBX Support", "enabled" ); php_info_print_table_row(2, "XMLDBX Session Serializer", "enabled" ); #else E2LOG("no PHP_SESSION"); php_info_print_table_row(2, "XMLDBX Support", "enabled" ); #endif php_info_print_table_end(); } /* }}} */ /* {{{ xmldbx_get_refattrs * Create a string of reference attributes */ static void xmldbx_get_refattrs(char *buffer, int cbbuf, zval *var) { int cb=0; if(var && (var->is_ref || var->refcount > 1)) { #ifdef ERR_DEBUG xmldbx_logf("REFATTR: %X, is_ref:%d, refcount: %d", var, var->is_ref, var->refcount); #endif cb = snprintf(buffer, cbbuf, XMLDBX_ATTRX, XA_REFERENCE, var); cbbuf -= cb; buffer+= cb; if(var->is_ref){ cb = snprintf(buffer, cbbuf, XMLDBX_ATTRN, XA_ISREF, 1); cbbuf -= cb; buffer+= cb; } if(var->refcount > 1){ cb = snprintf(buffer, cbbuf, XMLDBX_ATTRN, XA_REFCOUNT, var->refcount); cbbuf -= cb; buffer+= cb; } } *buffer = 0; } /* }}} */ /* {{{ xmldbx_write_var */ static void xmldbx_write_var(XMLDBXBUF *xmlbuf, int ntype, char *name, char *value, int len) { char *type = (ntype >= ST_IGNORE) ? XT_IGNORE : xmldbx_types[ntype]; char xmlname[2048]; char refattrs[128]; char *xname = name; #ifdef ERR_DEBUG xmldbx_logf("xmldbx_write_var(%s,%s,%s - isref:%d refcount:%d)", type, name, value, xmlbuf->zvalCurr->is_ref, xmlbuf->zvalCurr->refcount); #endif if(!len) len = strlen(value); // Open var with name or translated name if(xmldbx_bad_name(name)){ xmldbx_append_strf(xmlbuf, XMLDBX_OPEN_START, XST_XMLARG, type); xmldbx_append_strf(xmlbuf, XMLDBX_ATTRS, XA_NAME, name); xname = XST_XMLARG; } else { xmldbx_append_strf(xmlbuf, XMLDBX_OPEN_START, name, type); xname = name; } // <name [n='xname'] t='type' if(ntype == ST_REFERENCE) { // A reference is a string. xmldbx_append_strf(xmlbuf, XMLDBX_ATTRS, XA_VALUE, value); xmldbx_append_strf(xmlbuf, XMLDBX_OPEN_END_DEF); return; } xmldbx_get_refattrs(refattrs, sizeof(refattrs), xmlbuf->zvalCurr); smart_str_appends(&xmlbuf->str, refattrs); xmldbx_append_strf(xmlbuf, XMLDBX_ATTRS, XA_VALUE, value); xmldbx_append_strf(xmlbuf, XMLDBX_OPEN_END_DEF); } /* }}} */ /* {{{ xmldbx_open_var */ static char *xmldbx_open_var(XMLDBXBUF *xmlbuf, int ntype, char *name, char *classname, int len, char *extra) { char *type = (ntype >= ST_IGNORE) ?ST_NULL : xmldbx_types[ntype]; char xmlname[1024]; char refattrs[128]; char *xname = name; #ifdef ERR_DEBUG_EXTRA xmldbx_logf("xmldbx_open_var(%s,%s,%s) [%d]", type, name, classname, need_attrib); #endif // Open var with name or translated name if(xmldbx_bad_name(name)){ xmldbx_append_strf(xmlbuf, XMLDBX_OPEN_START , XST_XMLARG, type); xmldbx_append_strf(xmlbuf, XMLDBX_ATTRS, XA_NAME, name); xname = XST_XMLARG; } else { xmldbx_append_strf(xmlbuf, XMLDBX_OPEN_START, name, type); xname = name; } xmldbx_get_refattrs(refattrs, sizeof(refattrs), xmlbuf->zvalCurr); smart_str_appends(&xmlbuf->str, refattrs); if(len) xmldbx_append_strf(xmlbuf, XMLDBX_ATTRN, XA_LEN, len); if(classname) xmldbx_append_strf(xmlbuf, XMLDBX_ATTRS, XA_CLASSNAME, classname); if(extra) xmldbx_append_strf(xmlbuf, XMLDBX_ATTRS, XA_EXTRA, extra); xmldbx_append_strf(xmlbuf, ">"); E2LOG(xmlbuf->str.c); return xname; } /* }}} */ /* {{{ xmldbx_close_var */ static void xmldbx_close_var(XMLDBXBUF *xmlbuf, char *name) { xmldbx_append_strf(xmlbuf, XMLDBX_VAR_E, name); } /* }}} */ /* {{{ xmldbx_start */ static void xmldbx_start(XMLDBXBUF *xmlbuf) { ELOG_FUNC("xmldbx_start"); smart_str_appends(&xmlbuf->str, XMLDBX_NAME_S); } /* }}} */ /* {{{ xmldbx_end */ static void xmldbx_end(XMLDBXBUF *xmlbuf) { ELOG_FUNC("xmldbx_end"); smart_str_appends(&xmlbuf->str, XMLDBX_NAME_E); } /* }}} */ /***************** Serialize functions for basic types *******************/ static int xmldbx_bad_xmlchar(int c) { if(isalnum(c) || (c=='_') ) return 0; else if(c == '_') return 0; return 1; } static int xmldbx_bad_char(int c) { return (xmldbx_bad_xmlchar(c)==0 || c==' ') ? 0 : 1; } /* xmldbx_bad_name * Test is name not good for XML tag */ static int xmldbx_bad_name(char *src) { if(isdigit(*src)) return 1; while(*src){ if(xmldbx_bad_xmlchar(*src)) return 1; src++; } return 0; } /* }}} */ /* xmldbx_bad_string * Test is string not good inside XML tag */ static int xmldbx_bad_string(char *src) { while(*src){ if(xmldbx_bad_char(*src)) return 1; src++; } return 0; } /* }}} */ /* {{{ xmldbx_serialize_string */ static void xmldbx_serialize_string(XMLDBXBUF *xmlbuf, char *name, zval *var) { ELOG_FUNC("xmldbx_serialize_string"); if(var){ int cbsz = Z_STRLEN_P(var); char * value= Z_STRVAL_P(var); int cdata = 0; int i; if(cbsz == 0) // No string, no translate return; for(i=0; i < cbsz; i++){ if(xmldbx_bad_char(value[i])){ cdata = 1; break; } } if(cdata==0 && cbsz <XMLDBX_SMALLSZ){ // Small easy string, go for more efficienct one tag xmldbx_write_var(xmlbuf, ST_STRING, name, value, cbsz); } else { // Embed string in a CDATA to avoid parsing char *xname = xmldbx_open_var(xmlbuf, ST_STRING, name, NULL, 0, NULL); smart_str_appends(&xmlbuf->str, "<![CDATA["); smart_str_appendl(&xmlbuf->str, value, cbsz); smart_str_appends(&xmlbuf->str, "]]>"); xmldbx_close_var(xmlbuf, xname); } } } /* }}} */ static void CopyZvalString(char *dest, zval *src, int cbdest) { zval tmp; ELOG_FUNC("CopyZvalString"); tmp = *src; zval_copy_ctor(&tmp); convert_to_string(&tmp); strncpy(dest, Z_STRVAL(tmp), cbdest); ZDTOR(&tmp); } /* {{{ xmldbx_serialize_number */ static void xmldbx_serialize_number(XMLDBXBUF *xmlbuf, char *name,zval *var) { char buf[XMLDBX_BUF_LEN]; CopyZvalString(buf, var, sizeof(buf)); xmldbx_write_var(xmlbuf, ST_LONG, name, buf, 0); } /* }}} */ /* {{{ xmldbx_serialize_float */ static void xmldbx_serialize_float(XMLDBXBUF *xmlbuf, char *name,zval *var) { char buf[XMLDBX_BUF_LEN]; CopyZvalString(buf, var, sizeof(buf)); xmldbx_write_var(xmlbuf, ST_DOUBLE, name, buf, 0); } /* }}} */ /* {{{ xmldbx_serialize_boolean */ static void xmldbx_serialize_boolean(XMLDBXBUF *xmlbuf, char *name, zval *var) { ELOG_FUNC("xmldbx_serialize_boolean"); xmldbx_write_var(xmlbuf, ST_BOOLEAN, name,Z_LVAL_P(var) ? "t" : "f", 0); } /* }}} */ /* {{{ xmldbx_serialize_unset */ static void xmldbx_serialize_unset(XMLDBXBUF *xmlbuf, char *name) { ELOG_FUNC("xmldbx_serialize_unset"); xmldbx_write_var(xmlbuf, ST_NULL, name,XT_NULL, 0); } /* }}} */ /************ Functions serialize aggrgate object ********************/ #define ENUMA_START -1 #define ENUMA_END -2 // Enumerates all elements on an object or array static int EnumArray(zval *obj, EnumArrayCallback fn, void *p1, void *p2) { ArrayEnumStruct ae; // Initialize the structure ae.obj = obj; ae.ent = NULL; ae.hash = HASH_OF(obj); ae.pointer = NULL; ae.key = NULL; ae.keylen = 0; ae.p1 = p1; ae.p2 = p2; ae.private = NULL; int count=0; if(ae.hash) { E2LOG("Array Enum:Start"); /* call before enumeration */ ae.physndx = ae.ndx= ENUMA_START; if(!(*fn)(&ae)) return ae.ndx; ae.physndx = ae.ndx= 0; /* Enumerate all objects */ for (zend_hash_internal_pointer_reset_ex(ae.hash, &ae.pointer); zend_hash_get_current_data_ex(ae.hash, (void**)&ae.ent, &ae.pointer) == SUCCESS; zend_hash_move_forward_ex(ae.hash, &ae.pointer)) { ae.type = zend_hash_get_current_key_ex(ae.hash, &ae.key, &ae.keylen, &ae.ndx, 0, &ae.pointer); if(ae.ent) { if(*ae.ent != obj){ if(!(*fn)(&ae)) break; ae.physndx++; } } } count = ae.physndx; /* call after enumeration */ ae.physndx = ae.ndx= ENUMA_END; ae.ent = NULL; if(!(*fn)(&ae)) return ae.ndx; /* return count of objects */ E2LOG("Array Enum:End"); } return count; } /* Checks if there are non-numerical indexes in the array */ /* p1 is xmlbuf, p2 is NULL */ static int eaIsStruct(ArrayEnumStruct *ae) { ELOG("aeIsStruct"); int *is_struct = (int *) ae->p2; if(ae->ent) { if (ae->type == HASH_KEY_IS_STRING) { *is_struct = ST_OBJECT; return 0; // Done } if (ae->ndx != ae->physndx) { *is_struct = ST_OBJECT; return 0; // Done } } return 1; } /* Serializes array variable. */ /* p1 is xmlbuf, p2 is NULL */ static int aeSerializeVar(ArrayEnumStruct *ae) { ELOG("aeSerializeVar"); if(ae->ent && (*ae->ent != ae->obj) && (*ae->ent != ae->p2)) { XMLDBXBUF *xmlbuf = (XMLDBXBUF *) ae->p1; xmldbx_serialize_var(xmlbuf, *ae->ent, NULL, 0 TSRMLS_CC); } return 1; } /* Serializes a structure variable */ /* p1 is xmlbuf, p2 is NULL */ static int aeSerializeArrayVar(ArrayEnumStruct *ae) { ELOG("aeSerializeArrayVar"); XMLDBXBUF *xmlbuf = (XMLDBXBUF *) ae->p1; if(ae->ent && *ae->ent != ae->obj && *ae->ent != ae->p2) { if (ae->type == HASH_KEY_IS_STRING) { ELOG("HASH_KEY_IS_STRING"); xmldbx_serialize_var(xmlbuf, *ae->ent, ae->key, ae->keylen TSRMLS_CC); } else { char tmp_buf[XMLDBX_BUF_LEN]; ae->keylen = snprintf(tmp_buf, sizeof(tmp_buf),"%ld", ae->ndx); xmldbx_serialize_var(xmlbuf, *ae->ent, tmp_buf, ae->keylen TSRMLS_CC); } } return 1; } /* Serialize an object */ /* p1 is xmlbuf, p2 is parent object */ static int aeSerializeObjectVar(ArrayEnumStruct *ae) { ELOG("aeSerializeObjectVar"); zval *lent; char *varname = Z_STRVAL_PP(ae->ent); int varlen = (varname) ? strlen(varname)+1 : 0; if(ae->ent && *ae->ent != ae->obj && *ae->ent != ae->p2) { XMLDBXBUF *xmlbuf = (XMLDBXBUF *) ae->p1; if (Z_TYPE_PP(ae->ent) != IS_STRING) { php_error(E_NOTICE, "__sleep should return an array only containing the names of instance-variables to serialize."); } else if (zend_hash_find(HASH_OF(((zval *)ae->p2)),varname,varlen,(void **)&lent) == SUCCESS) { xmldbx_serialize_var(xmlbuf, lent, varname, varlen TSRMLS_CC); } } return 1; } /* {{{ xmldbx_serialize_array */ static void xmldbx_serialize_array(XMLDBXBUF *xmlbuf, char *name, zval *arr) { int is_struct = ST_ARRAY; char *xname=NULL; int count; char *extra=NULL; TSRMLS_FETCH(); ELOG_FUNC("xmldbx_serialize_array"); /* discover if array containes string keys! */ count = EnumArray(arr, eaIsStruct, xmlbuf, (void *)&is_struct); #ifdef DUMP_DEBUG if(is_struct) extra = "st"; else extra = "var"; #endif xname = xmldbx_open_var(xmlbuf, is_struct, name, NULL, count, extra); if(is_struct) EnumArray(arr, aeSerializeArrayVar, (void *) xmlbuf, NULL); else EnumArray(arr, aeSerializeVar, (void *) xmlbuf, NULL); xmldbx_close_var(xmlbuf, xname); } /* }}} */ /* {{{ xmldbx_serialize_object */ static void xmldbx_serialize_object(XMLDBXBUF *xmlbuf, char *name, zval *obj) { zval *fname=NULL; zval *varnames=NULL; char *xname=NULL; char *extra = NULL; TSRMLS_FETCH(); MAKE_STD_ZVAL(fname); ZVAL_STRING(fname, "__sleep", 1); ELOG_FUNC("xmldbx_serialize_object"); /* We try to call __sleep() method on object. It's supposed to return an * array of property names to be serialized. We will walk the array of names * not the array itself*/ if (call_user_function_ex(CG(function_table), &obj, fname, &varnames, 0, 0, 1, NULL TSRMLS_CC) != SUCCESS) varnames = NULL; PHP_CLASS_ATTRIBUTES; PHP_SET_CLASS_ATTRIBUTES(obj); E2LOG(class_name); E2LOG(name); #ifdef DUMP_DEBUG if(varnames && HASH_OF(varnames)) extra = "HASHOF_varnames"; else if(varnames) extra = "varnames"; else extra = "obj"; #endif xname = xmldbx_open_var(xmlbuf, ST_OBJECT, name, class_name, 0, extra); PHP_CLEANUP_CLASS_ATTRIBUTES(); if(varnames && HASH_OF(varnames)) EnumArray(varnames, aeSerializeObjectVar, (void *) xmlbuf, obj); else EnumArray(obj, aeSerializeArrayVar, (void *) xmlbuf, obj); xmldbx_close_var(xmlbuf, xname); ZDTOR(fname); FREE_ZVAL(fname); } /* }}} */ /* {{{ xmldbx_find_type * Returns a static type */ static int xmldbx_find_ztype(int ztype) { #if 0 /* Remove, re-aligned values with Zend */ int type=ST_NULL; switch(ztype) { case IS_NULL: type = ST_NULL; break; case IS_BOOL: type = ST_BOOLEAN; break; case IS_LONG: type = ST_LONG; break; case IS_DOUBLE: type = ST_DOUBLE; break; case IS_STRING: type = ST_STRING; break; case IS_RESOURCE: type = ST_RESOURCE; break; case IS_ARRAY: type = ST_ARRAY; break; case IS_OBJECT: type = ST_OBJECT; break; } return type; #else if(ztype >= IS_NULL && ztype <= IS_RESOURCE) return ztype; #ifdef ERR_DEBUG xmldbx_logf("TYPE Error: %d", ztype); #endif return ST_STRING; #endif } /* {{{ xmldbx_serialize_var * All variables start here!! */ void xmldbx_serialize_var(XMLDBXBUF *xmlbuf, zval *var, char *name, int name_len TSRMLS_DC) { char *name_esc=NULL; int name_esc_len; int ntype; int ztype = Z_TYPE_P(var); int i; ELOG_FUNC("xmldbx_serialize_var"); ntype = xmldbx_find_ztype(ztype); xmlbuf->zvalCurr = var; if (name) { name_esc = php_escape_html_entities(name, name_len, &name_esc_len, 0, ENT_QUOTES, NULL TSRMLS_CC); name = name_esc; } else { name = XST_UNNAMED; } if(var->refcount > 1 || var->is_ref){ if(xmldbx_find_dupzval(&xmlbuf->zentry, name, var)) { char buffer[64]; int len = snprintf(buffer, sizeof(buffer), "%X", var); xmldbx_write_var(xmlbuf, ST_REFERENCE, name, buffer, len); return ; } xmldbx_push_zval(&xmlbuf->zentry, name, var); } switch(ztype) { case IS_BOOL: xmldbx_serialize_boolean(xmlbuf, name, var); break; case IS_NULL: xmldbx_serialize_unset(xmlbuf, name); break; case IS_LONG: xmldbx_serialize_number(xmlbuf, name, var); break; case IS_DOUBLE: xmldbx_serialize_float(xmlbuf, name, var); break; case IS_STRING: xmldbx_serialize_string(xmlbuf, name, var); break; case IS_OBJECT: xmldbx_serialize_object(xmlbuf, name, var); break; case IS_ARRAY: xmldbx_serialize_array(xmlbuf, name, var); break; #ifdef ERR_DEBUG case IS_RESOURCE: ELOG("ERROR: Serializing a resource"); break; #endif default: xmldbx_logf("Error: Serialize unknown type: %d", ztype); xmldbx_write_var(xmlbuf, ST_IGNORE, name, NULL, 0); break; } if(name_esc) FREEMEM(name_esc); } /* }}} */ /* {{{ xmldbx_add_var * Recusively calls itself on complex types * Basically php interface for xmldbx_serialize_var */ static void xmldbx_add_var(XMLDBXBUF *xmlbuf, zval *name_var) { zval **val=NULL; HashTable *target_hash=NULL; TSRMLS_FETCH(); ELOG_FUNC("xmldbx_add_var"); if (Z_TYPE_P(name_var) == IS_STRING) { if (zend_hash_find(EG(active_symbol_table), Z_STRVAL_P(name_var), Z_STRLEN_P(name_var)+1, (void**)&val) != FAILURE) { xmldbx_serialize_var(xmlbuf, *val, Z_STRVAL_P(name_var), Z_STRLEN_P(name_var) TSRMLS_CC); } } else if (Z_TYPE_P(name_var) == IS_ARRAY || Z_TYPE_P(name_var) == IS_OBJECT) { target_hash = HASH_OF(name_var); zend_hash_internal_pointer_reset(target_hash); while(zend_hash_get_current_data(target_hash, (void**)&val) == SUCCESS) { xmldbx_add_var(xmlbuf, *val); zend_hash_move_forward(target_hash); } } } /* {{{ xmldbx_set_classname * Sets the class name/type of an object */ static void xmldbx_set_classname(zval ** data, char *classname) { ELOG_FUNC("xmldbx_set_classname"); zend_bool empty_class = 0; zend_class_entry *ce=NULL; zval *obj=NULL; zval *tmp=NULL; int cbcls = strlen(classname); zend_str_tolower(classname, cbcls); #ifdef ERR_DEBUG xmldbx_logf("classname: classname: %s, namelen: %d", classname, cbcls); #endif if(zend_hash_find(EG(class_table), classname, cbcls+1, (void **)&ce) == FAILURE) { ce = PHP_IC_ENTRY; empty_class = 1; } MAKE_STD_ZVAL(obj); INIT_PZVAL(obj); object_init_ex(obj,ce); zend_hash_merge(Z_OBJPROP_P(obj), Z_ARRVAL_P(*data), (void (*)(void *)) zval_add_ref, (void *) &tmp, sizeof(zval *), 0); if(empty_class) php_store_class_name(obj, classname, cbcls TSRMLS_CC); ZDTORP(data); *data = obj; } /* }}} */ /* {{{ xmldbx_start_handler * This function takes the information in the XML bracket, and extracts the type from * the atributes. */ static void xmldbx_start_handler(void *data, const XML_Char *name, const XML_Char **atts) { xmldbx_tag ent; ELOG_FUNC("xmldbx_start_handler"); xmldbx_stack * stack = (xmldbx_stack *) data; /* Get atributes */ XML_Char *xml_type = xmldbx_find_attr(XA_TYPE, atts); XML_Char *xml_value = xmldbx_find_attr(XA_VALUE, atts); XML_Char *xml_vname = xmldbx_find_attr(XA_NAME, atts); XML_Char *xml_classname = xmldbx_find_attr(XA_CLASSNAME, atts); XML_Char *xml_isref = xmldbx_find_attr(XA_ISREF, atts); XML_Char *xml_zref = xmldbx_find_attr(XA_REFERENCE, atts); XML_Char *xml_rcnt = xmldbx_find_attr(XA_REFCOUNT, atts); if(!xml_type) xml_type = XT_IGNORE; ent.type = ST_IGNORE; ent.data = NULL; ent.items = 0; ent.xname = (name) ? estrdup(name) : NULL; ent.vname = (xml_vname) ? estrdup(xml_vname) : ent.xname; #ifdef ZVAL_DEBUG xmldbx_logf("push: %d, %s(%s):%s[%s] zref:%s rcnt:%s", stack->top, ent.xname, ent.vname, xml_type, (xml_value) ? xml_value : "", (xml_zref) ? xml_zref : "", (xml_rcnt) ? xml_rcnt : ""); #endif if(stack->state == XPS_IDLE){ // We haven't started yet E2LOG("State is idle"); if(!strcmp(name, XST_NAME)) { // Should be the beginning xmlbuf! char *version = xmldbx_find_attr(XA_VERSION, atts); if(strcmp(version, XMLDBX_VERSION)) // Bad version, what to do? xmldbx_logf("Bad data format: xmldbx version=%s, not %s\n", version, XMLDBX_VERSION); else stack->state = XPS_XMLDBX; // We are processing xmldbx data memset(&ent,0,sizeof(ent)); ent.type = ST_NAME; ent.data = NULL; E2LOG("ST_NAME"); } } else if (!strcmp(xml_type, XT_STRING)) { // A standard string ent.type = ST_STRING; ALLOC_ZVAL(ent.data); INIT_PZVAL(ent.data); Z_TYPE_P(ent.data) = IS_STRING; Z_STRVAL_P(ent.data) = xmldbx_empty_string; Z_STRLEN_P(ent.data) = 0; E2LOG("ST_STRING"); } else if (!strcmp(xml_type, XT_LONG)) { // A number ent.type = ST_LONG; ALLOC_ZVAL(ent.data); INIT_PZVAL(ent.data); Z_TYPE_P(ent.data) = IS_LONG; E2LOG("ST_LONG"); } else if (!strcmp(xml_type, XT_DOUBLE)) { // A number ent.type = ST_DOUBLE; ALLOC_ZVAL(ent.data); INIT_PZVAL(ent.data); Z_TYPE_P(ent.data) = IS_DOUBLE; E2LOG("ST_LONG"); } else if (!strcmp(xml_type, XT_BOOLEAN)) { ent.type = ST_BOOLEAN; ALLOC_ZVAL(ent.data); INIT_PZVAL(ent.data); Z_TYPE_P(ent.data) = IS_BOOL; E2LOG("ST_BOOLEAN"); } else if (!strcmp(xml_type, XT_NULL)) { ent.type = ST_NULL; ALLOC_ZVAL(ent.data); INIT_PZVAL(ent.data); ZVAL_NULL(ent.data); E2LOG("ST_NULL"); } else if (!strcmp(xml_type, XT_ARRAY)) { ent.type = ST_ARRAY; ALLOC_ZVAL(ent.data); array_init(ent.data); INIT_PZVAL(ent.data); E2LOG("ST_ARRAY"); } else if (!strcmp(xml_type, XT_OBJECT)) { ent.type = ST_OBJECT; ALLOC_ZVAL(ent.data); array_init(ent.data); INIT_PZVAL(ent.data); E2LOG("ST_OBJECT"); } else if(!strcmp(xml_type, XT_REFERENCE)) { // Ignore indexes greater than 1 as they are generally ignored in // PHP itself. ent.type = ST_REFERENCE; ent.data = NULL; int i; #ifdef ZVAL_DEBUG xmldbx_logf("Read XML REFERENCE offset %s", xml_value); #endif if(xml_value){ // Make sure we don't do something to the value for(i=0; i < stack->zentry.nzvals; i++) { if(!strcmp(stack->zentry.zvals[i].name, xml_value)) { #ifdef ZVAL_DEBUG xmldbx_logf("Found a reference!!! %s, %s", ent.vname, xml_value); #endif ent.data = stack->zentry.zvals[i].obj; break; } } #ifdef ZVAL_DEBUG // This should be a bug, but I think NULL values are valid, this will // just make them go away. if(!ent.data) php_error(E_WARNING, "XML REFERENCE not found ignoring:%s", xml_value); #endif } else php_error(E_WARNING, "Bogus XML REFERENCE"); xml_value = NULL; } #ifdef ERR_DEBUG else { xmldbx_logf("Unknown type %s", xml_type); } #endif if(ent.type != ST_REFERENCE && ent.data){ if(xml_isref) ent.data->is_ref = 1; if(xml_rcnt) ent.data->refcount=atoi(xml_rcnt); if(xml_zref) xmldbx_push_zval(&stack->zentry, xml_zref, ent.data); } if(xml_classname && (ent.type == ST_ARRAY || ent.type == ST_OBJECT)) xmldbx_set_classname(&ent.data, xml_classname); xmldbx_stack_push(stack, &ent); if(ent.type != ST_IGNORE && xml_value){ xmldbx_data_handler(stack, xml_value, strlen(xml_value)); } } /* }}} */ /* {{{ xmldbx_end_handler * Called at the end of an XML tag, decides what to do with it. */ static void xmldbx_end_handler(void *user_data, const XML_Char *name) { xmldbx_tag entCurr; xmldbx_tag * pentParent=NULL; HashTable * target_hash=NULL; xmldbx_stack * stack = (xmldbx_stack *)user_data; TSRMLS_FETCH(); ELOG_FUNC("xmldbx_end_handler"); if(stack->top == 0) { #ifdef ERR_DEBUG xmldbx_logf("Top of stack: %s", (name) ? name : "unknown"); #endif return; } // Pop var off stack xmldbx_stack_pop(stack, &entCurr); // Get parent stack entry xmldbx_stack_curr(stack, &pentParent); if(entCurr.xname && strcmp(name, entCurr.xname)){ xmldbx_logf("Warning: name and xname out of sync! \"%s\" != \"%s\"", name, (entCurr.xname) ? entCurr.xname : "NULL" ); } if((entCurr.type == ST_IGNORE) || (entCurr.data == NULL)) { xmldbx_clear_tag(&entCurr); return; } #ifdef ERR_DEBUG if(((int)name) < 65536) { xmldbx_logf("Really funky pointer:%X !!", name); } xmldbx_logf("pop: %d, name %s, entCurr:%s, pentParent:%s", stack->top, name, entCurr.vname, (pentParent) ? pentParent->vname : "NULL"); if(pentParent) { xmldbx_logf("pentParent: %X, pentParent->data: %X", pentParent, pentParent->data); } #endif /* Call __wakeup() method on the object. */ if (Z_TYPE_P(entCurr.data) == IS_OBJECT) { zval *fname = NULL; zval *retval = NULL; MAKE_STD_ZVAL(fname); ZVAL_STRING(fname, "__wakeup", 1); call_user_function_ex(NULL, &entCurr.data, fname, &retval, 0, 0, 0, NULL TSRMLS_CC); ZDTOR(fname); FREE_ZVAL(fname); if (retval) ZDTOR(retval); } if(!pentParent){ ELOG("Last tagfound"); xmldbx_stack_set_return(stack, &entCurr); } else { if(pentParent->type == ST_NAME || stack->top == 1) { ELOG("Parent found"); xmldbx_stack_set_return(stack, &entCurr); } else if (pentParent->data) { // This is the main method by which data is returned. // Discrete objects MUST be part of some sort of container // If the parent is a container! if (Z_TYPE_P(pentParent->data) == IS_ARRAY || Z_TYPE_P(pentParent->data) == IS_OBJECT) { target_hash = HASH_OF(pentParent->data); if (strcmp(entCurr.vname, XST_UNNAMED)) { // If it is a named entry zend_hash_update(target_hash, entCurr.vname, strlen(entCurr.vname)+1, &entCurr.data, sizeof(zval *), NULL); } else { // Does not have a name zend_hash_next_index_insert(target_hash, &entCurr.data, sizeof(zval *), NULL); } } } #ifdef ERR_DEBUG else { ELOG("Parent type not ST_NAME and no data, data lost"); } #endif } xmldbx_clear_tag(&entCurr); } /* }}} */ /* {{{ xmldbx_data_handler * Interprets the type on the stack and applys data accordingly */ static void xmldbx_data_handler(void *user_data, const XML_Char *s, int len) { xmldbx_tag *ent=NULL; xmldbx_stack *stack = (xmldbx_stack *)user_data; char *decoded=NULL; int decoded_len; TSRMLS_FETCH(); ELOG_FUNC("xmldbx_data_handler"); if(stack->state == XPS_DONE) // We be done, just walk away return; ELOG_FUNC("xmldbx_data_handler"); if (!xmldbx_stack_is_empty(stack)) { xmldbx_stack_curr(stack, &ent); switch (ent->type) { case ST_STRING: ELOG("xml->string"); decoded = (char *)xml_utf8_decode(s, len, &decoded_len, "ISO-8859-1"); if(decoded) { if (Z_STRLEN_P(ent->data) == 0) { Z_STRVAL_P(ent->data) = estrndup(decoded, decoded_len); Z_STRLEN_P(ent->data) = decoded_len; } else { Z_STRVAL_P(ent->data) = erealloc(Z_STRVAL_P(ent->data), Z_STRLEN_P(ent->data) + decoded_len + 1); strncpy(Z_STRVAL_P(ent->data)+Z_STRLEN_P(ent->data), decoded, decoded_len); Z_STRLEN_P(ent->data) += decoded_len; Z_STRVAL_P(ent->data)[Z_STRLEN_P(ent->data)] = '\0'; } FREEMEM(decoded); } break; case ST_DOUBLE: ELOG("xml->double"); Z_TYPE_P(ent->data) = IS_STRING; Z_STRLEN_P(ent->data) = len; Z_STRVAL_P(ent->data) = estrndup(s, len); convert_to_double(ent->data); break; case ST_LONG: ELOG("xml->long"); Z_TYPE_P(ent->data) = IS_STRING; Z_STRLEN_P(ent->data) = len; Z_STRVAL_P(ent->data) = estrndup(s, len); convert_to_long(ent->data); break; case ST_BOOLEAN: ELOG("xml->bool"); Z_LVAL_P(ent->data) = (*s == 't') ? 1 : 0; break; default: break; } } } /* }}} */ /* {{{ xmldbx_deserialize_xml * Called to deserialize */ int xmldbx_deserialize_xml(zval **zret, const char *value, int vallen) { xmldbx_stack stack; XML_Parser parser; xmldbx_tag *ent=NULL; int retval; ELOG_FUNC("xmldbx_deserialize_xml"); xmldbx_stack_init(&stack); MAKE_STD_ZVAL(stack.retval); stack.endtag = XST_DATA; parser = XML_ParserCreate("ISO-8859-1"); XML_SetUserData(parser, &stack); XML_SetElementHandler(parser, xmldbx_start_handler, xmldbx_end_handler); XML_SetCharacterDataHandler(parser, xmldbx_data_handler); if(XML_Parse(parser, value, vallen, 1)==0) { char buffer[1024]; int ec = XML_GetErrorCode(parser); char *s = (char *)XML_ErrorString(ec); snprintf(buffer, sizeof(buffer), "XML Parsing Error: %s", s); php_error(E_WARNING, buffer); #ifdef LOG_BAD_PARSE xmldbx_log_string("parse_err_", value); #endif } XML_ParserFree(parser); *zret = xmldbx_stack_get_return(&stack); xmldbx_stack_destroy(&stack); if(*zret) { ELOG("xmldbx_deserialize_xml SUCCESS"); return SUCCESS; } else { ELOG("xmldbx_deserialize_xml FAILURE"); return FAILURE; } } /* }}} */ /* {{{ xmldbx_constructor */ static XMLDBXBUF *xmldbx_constructor(void) { XMLDBXBUF *xmlbuf=NULL; ELOG_FUNC("xmldbx_constructor"); xmlbuf = (XMLDBXBUF *)ALLOCMEM(sizeof(XMLDBXBUF)); memset(xmlbuf, 0, sizeof(XMLDBXBUF)); xmldbx_zentry_init(&xmlbuf->zentry); return xmlbuf; } /* }}} */ /* {{{ xmldbx_destructor */ static void xmldbx_destructor(XMLDBXBUF *xmlbuf) { ELOG_FUNC("xmldbx_destructor"); smart_str_free(&xmlbuf->str); xmldbx_zentry_destroy(&xmlbuf->zentry); FREEMEM(xmlbuf); } /* }}} */ char *xmldbx_serialize_xml(char *name, zval **obj) { XMLDBXBUF *xmlbuf=xmldbx_constructor(); if (!xmlbuf) { return NULL; } else { xmldbx_start(xmlbuf); xmldbx_serialize_var(xmlbuf, *obj, name, strlen(name) TSRMLS_DC); xmldbx_end(xmlbuf); name = estrndup(xmlbuf->str.c, xmlbuf->str.len); xmldbx_destructor(xmlbuf); ELOG(name); return name; } } #ifdef HAS_PHP_XMLDBX_FUNCTIONS /* {{{ proto string xmldbx_serialize(string varname, mixed object) Creates a new xmlbuf and serializes given variables into a struct */ PHP_FUNCTION(xmldbx_serialize) { int argc, i; char *xname=NULL; zval **obj; zval **name; ELOG_FUNC("PHP_FUNCTION(xmldbx_serialize)"); argc = ZEND_NUM_ARGS(); if (argc != 2) { php_error(E_WARNING, "%s() array to be serialized, 0 given", get_active_function_name(TSRMLS_C)); return; } if (zend_get_parameters_ex(2, &name, &obj) == FAILURE) { RETURN_FALSE; } convert_to_string_ex(name); xname = Z_STRVAL_PP(name); xname = xmldbx_serialize_xml(Z_STRVAL_PP(name), obj); if(xname) { RETURN_STRING(xname,0) } } /* }}} */ /* {{{ proto mixed xmldbx_deserialize(string xmlbuf) Deserializes given xmlbuf and returns a PHP value */ PHP_FUNCTION(xmldbx_deserialize) { char *xmlbuf=NULL; int xmlbuf_len; xmldbx_stack stack; zval **zxml; zval *zret; ELOG_FUNC("PHP_FUNCTION(xmldbx_deserialize)"); if(ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &zxml) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string_ex(zxml); xmlbuf = Z_STRVAL_PP(zxml); xmlbuf_len = strlen(xmlbuf); if (xmlbuf_len == 0) return; xmldbx_deserialize_xml(&zret, xmlbuf, xmlbuf_len); *return_value = *zret; } /* }}} */ #endif // HAS_PHP_XMLDBX_FUNCTIONS #endif /* HAVE_LIBEXPAT */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: sw=4 ts=4 fdm=marker * vim<600: sw=4 ts=4 */ http://cvs.php.net/viewcvs.cgi/php-src/ext/xmldbx/xmldbx.h?view=markup&rev=1.1 Index: php-src/ext/xmldbx/xmldbx.h +++ php-src/ext/xmldbx/xmldbx.h /* +----------------------------------------------------------------------+ | PHP Version 4 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2003 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 2.02 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available at through the world-wide-web at | | http://www.php.net/license/2_02.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: markw@mohawksoft.com | +----------------------------------------------------------------------+ */ #ifndef PHP_XMLDBX_API_H #define PHP_XMLDBX_API_H #ifdef XMLDBX_USING_PHP #include "ext/standard/php_smart_str.h" #endif // Generic XML header #define XMLDBX_NAME_S "<xmldbx version='1.0'>" #define XMLDBX_NAME_E "</xmldbx>" #define XMLDBX_VERSION "1.0" // XML String ags #define XST_UNNAMED "unnamed" #define XST_DATA "data" #define XST_NAME "xmldbx" #define XST_XMLARG "xag" // Value tag variants // Many probably unused #define XMLDBX_OPEN_START "<%s t='%s' " #define XMLDBX_OPEN_END_DEF "/>" #define XMLDBX_OPEN_END ">" #define XMLDBX_VAR_S "<%s>" #define XMLDBX_VAR_ST "<%s t='%s'>" #define XMLDBX_VAR_STAN "<%s t='%s' %s='%d'>" #define XMLDBX_VAR_STA "<%s t='%s' %s='%s'>" #define XMLDBX_VAR_STAA "<%s t='%s' %s='%s' %s='%s'>" #define XMLDBX_VAR_STAAN "<%s t='%s' %s='%s' %s='%d'>" #define XMLDBX_VAR_STN "<%s t='%s' len='%d'>" #define XMLDBX_VAR_E "</%s>" #define XMLDBX_VAR_STV "<%s t='%s' v='%s'/>" #define XMLDBX_VAR_STVAN "<%s t='%s' v='%s' %s='%d'/>" #define XMLDBX_VAR_STVA "<%s t='%s' v='%s' %s='%s'/>" #define XMLDBX_ATTRS "%s='%s' " #define XMLDBX_ATTRN "%s='%d' " #define XMLDBX_ATTRX "%s='%X' " // XML Attributes #define XA_VALUE "v" #define XA_VERSION "version" #define XA_TYPE "t" #define XA_CLASSNAME "cn" #define XA_NAME "nm" #define XA_LEN "cb" #define XA_EXTRA "ex" #define XA_REFERENCE "R" #define XA_REFCOUNT "C" #define XA_ISREF "I" // XML Types #define XT_NULL "null" #define XT_LONG "l" #define XT_DOUBLE "f" #define XT_STRING "sz" #define XT_ARRAY "a" #define XT_OBJECT "o" #define XT_BOOLEAN "b" #define XT_RESOURCE "rc" #define XT_CONSTANT "cn" #define XT_CONSTANT_ARRAY "cna" #define XT_REFERENCE "r" #define XT_NAME "n" #define XT_IGNORE "ig" // This enum matches the above set of XML Types enum XMLDBX_data_types{ ST_NULL, /* 0 */ ST_LONG, /* 1 */ ST_DOUBLE, /* 2 */ ST_STRING, /* 3 */ ST_ARRAY, /* 4 */ ST_OBJECT, /* 5 */ ST_BOOLEAN, /* 6 */ ST_RESOURCE, /* 7 */ ST_CONSTANT, /* 8 */ ST_CONSTANT_ARRAY, /* 9 */ ST_REFERENCE, /* 10 */ ST_NAME, /* 11 */ ST_IGNORE /* 12 */ }; /** Standard operation definitions */ #define XMLDBX_BUF_LEN 1024 #define XMLDBX_SMALLSZ (XMLDBX_BUF_LEN/4) /** starting size of zval stack */ #define XMLDBX_ZSTACK_SIZE 256 /** Starting size of XML stack */ #define XMLDBX_STACK_SIZE 32 /** The state of the XML parser */ enum PROC_STATE { XPS_IDLE, XPS_XMLDBX, XPS_DONE, XPS_UNKNOWN }; /** XML Parser tags */ typedef struct _xmldbx_stack_tags{ int type; // Data type int items; // How many items have been added char * xname; // XML Name of variable char * vname; // Real Var name zval * data; // Eventual data } xmldbx_tag; /** Types for zval stack */ typedef struct _xmldbx_zvals { zval * obj; char * name; }ZVAL_ENTRY; typedef struct _xmldbx_zval_array { int nzvals; int maxzvals; ZVAL_ENTRY *zvals; }ZVAL_ENTRIES; /** XML parse stack */ typedef struct { int top; // Top of stack int max; // Max depth int state; // Where we are and what we're doing zval* retval; // Data hash char * endtag; // The tag we are looking for (optional) ZVAL_ENTRIES zentry; // Track zvals xmldbx_tag * tags; // XML tag stack } xmldbx_stack; /** Types for Array enumeration */ typedef struct _ArrayEnumStruct { zval * obj; // The object ebing enumerated zval ** ent; // The current entry HashTable * hash; // The HASH_OF pointer HashPosition pointer; // The current position char * key; // The Current key int keylen; // The current key length ulong ndx; // The retrieved index number ulong physndx; // The "natural" loop index int type; // The returned type void * p1; // Passed parameter 1 void * p2; // Passed parameter 2 void * private; // Private data for function }ArrayEnumStruct; typedef int (*EnumArrayCallback)(ArrayEnumStruct *ae); typedef struct _xmldbx_xmlbuf { smart_str str; // The smart string for XML creation zval * zvalCurr; // Current zval ZVAL_ENTRIES zentry; // Track zvals }XMLDBXBUF; /* Make sure Zend agrees! #define IS_NULL 0 #define IS_LONG 1 #define IS_DOUBLE 2 #define IS_STRING 3 #define IS_ARRAY 4 #define IS_OBJECT 5 #define IS_BOOL 6 #define IS_RESOURCE 7 #define IS_CONSTANT 8 #define IS_CONSTANT_ARRAY 9 */ /* Good old fashioned debugging */ #ifdef ERR_DEBUG #define ELOG_FUNC( str ) xmldbx_logf("%s,%d (%s)", __FILE__,__LINE__,str) #define ELOG( str ) xmldbx_logf("%s,%d (%s)", __FILE__,__LINE__,str) #else #define ELOG_FUNC( str ) #define ELOG( str ) #endif #ifdef ERR_DEBUG_EXTRA #define E2LOG_FUNC( str ) xmldbx_logf("%s,%d (%s)", __FILE__,__LINE__,str) #define E2LOG( str ) xmldbx_logf("%s,%d (%s)", __FILE__,__LINE__,str) #else #define E2LOG_FUNC( str ) #define E2LOG( str ) #endif typedef smart_str xmldbx_buffer; #endif /* PHP_XMLDBX_API_H */ http://cvs.php.net/viewcvs.cgi/php-src/ext/xmldbx/xmldbx.php?view=markup&rev=1.1 Index: php-src/ext/xmldbx/xmldbx.php +++ php-src/ext/xmldbx/xmldbx.php <? # xmldbx.php # Test xmldbx session serializer # class MyClass { var $count; var $mybool; var $mystring; function print_vars() { print "count = " . $this->count . "<br>\n"; print "bybool = " . $this->mybool . "<br>\n"; print "mystring = " . $this->mystring . "<br>\n"; $this->count++; if($this->mybool == True) $this->mybool = False; else $this->mybool = True; $this->mystring = $this->mystring . "+"; } }; # Start sessions, this will set a cookie. session_start(); $sid = $HTTP_COOKIE_VARS["PHPSESSID"]; session_register("count"); session_register("setarray"); session_register("mycls"); session_register("myinit"); session_register("mybool"); session_register("myfloat"); session_register("myint"); if(!$myinit) { $mycls = new MyClass(); $myinit = true; $mybool = true; $myfloat = 1.1; $myint = 1; } if($mybool) $mybool = false; else $mybool = true; echo "mybool: ". $mybool . "<br>"; $myfloat = $myfloat + 1.1; $myint = $myint + 1; echo "myfloat: ". $myfloat . "<br>"; echo "myint: ". $myint . "<br>"; $count++; if($count < 2) { $_SESSION['setarray'] = array(); $_SESSION['setarray']['time']=time(); $_SESSION['setarray']['name1'] = 'xml_test1'; $_SESSION['setarray']['name2'] = 'xml_test2'; $_SESSION['setarray']['name3'] = 'xml_test3'; $_SESSION['setarray']['name4'] = 'xml_test4'; $_SESSION['setarray']['name5'] = 'xml_test5'; $_SESSION['setarray']['name6'] = 'xml_test6'; $_SESSION['setarray']['name7'] = 'xml_test7'; } echo $_SESSION['setarray']['name1'] . "<br>\n"; echo $_SESSION['setarray']['name2'] . "<br>\n"; echo $_SESSION['setarray']['name3'] . "<br>\n"; echo $_SESSION['setarray']['name4'] . "<br>\n"; echo $_SESSION['setarray']['name5'] . "<br>\n"; echo $_SESSION['setarray']['name6'] . "<br>\n"; echo $_SESSION['setarray']['name7'] . "<br>\n"; $mycls->print_vars(); # Output some information. echo "sid: " . $sid . "<br>\n"; echo "Session Count: " . $count . "<br>\n"; $xmlbuf = xmldbx_serialize("MyClass", $mycls); echo "XMLBUF: <xmp>" . $xmlbuf . "</xmp><BR>\n"; $test = xmldbx_deserialize($xmlbuf); $test->print_vars(); ?>
« previous php.cvs (#36657) next »