2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2013 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: Andrei Zmievski <andrei@php.net> |
16 +----------------------------------------------------------------------+
29 #include "ext/xml/expat_compat.h"
31 #include "php_wddx_api.h"
33 #define PHP_XML_INTERNAL
34 #include "ext/xml/php_xml.h"
35 #include "ext/standard/php_incomplete_class.h"
36 #include "ext/standard/base64.h"
37 #include "ext/standard/info.h"
38 #include "ext/standard/php_smart_str.h"
39 #include "ext/standard/html.h"
40 #include "ext/standard/php_string.h"
41 #include "ext/date/php_date.h"
42 #include "zend_globals.h"
44 #define WDDX_BUF_LEN 256
45 #define PHP_CLASS_NAME_VAR "php_class_name"
47 #define EL_ARRAY "array"
48 #define EL_BINARY "binary"
49 #define EL_BOOLEAN "boolean"
50 #define EL_CHAR "char"
51 #define EL_CHAR_CODE "code"
52 #define EL_NULL "null"
53 #define EL_NUMBER "number"
54 #define EL_PACKET "wddxPacket"
55 #define EL_STRING "string"
56 #define EL_STRUCT "struct"
57 #define EL_VALUE "value"
59 #define EL_NAME "name"
60 #define EL_VERSION "version"
61 #define EL_RECORDSET "recordset"
62 #define EL_FIELD "field"
63 #define EL_DATETIME "dateTime"
65 #define php_wddx_deserialize(a,b) \
66 php_wddx_deserialize_ex((a)->value.str.val, (a)->value.str.len, (b))
68 #define SET_STACK_VARNAME \
69 if (stack->varname) { \
70 ent.varname = estrdup(stack->varname); \
71 efree(stack->varname); \
72 stack->varname = NULL; \
103 static void php_wddx_process_data(void *user_data
, const XML_Char
*s
, int len
);
106 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_serialize_value
, 0, 0, 1)
107 ZEND_ARG_INFO(0, var
)
108 ZEND_ARG_INFO(0, comment
)
111 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_serialize_vars
, 0, 0, 1)
112 ZEND_ARG_INFO(0, var_name
)
113 ZEND_ARG_INFO(0, ...)
116 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_serialize_start
, 0, 0, 0)
117 ZEND_ARG_INFO(0, comment
)
120 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_packet_end
, 0, 0, 1)
121 ZEND_ARG_INFO(0, packet_id
)
124 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_add_vars
, 0, 0, 2)
125 ZEND_ARG_INFO(0, packet_id
)
126 ZEND_ARG_INFO(0, var_name
)
127 ZEND_ARG_INFO(0, ...)
130 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_deserialize
, 0, 0, 1)
131 ZEND_ARG_INFO(0, packet
)
135 /* {{{ wddx_functions[]
137 const zend_function_entry wddx_functions
[] = {
138 PHP_FE(wddx_serialize_value
, arginfo_wddx_serialize_value
)
139 PHP_FE(wddx_serialize_vars
, arginfo_wddx_serialize_vars
)
140 PHP_FE(wddx_packet_start
, arginfo_wddx_serialize_start
)
141 PHP_FE(wddx_packet_end
, arginfo_wddx_packet_end
)
142 PHP_FE(wddx_add_vars
, arginfo_wddx_add_vars
)
143 PHP_FE(wddx_deserialize
, arginfo_wddx_deserialize
)
148 PHP_MINIT_FUNCTION(wddx
);
149 PHP_MINFO_FUNCTION(wddx
);
151 /* {{{ dynamically loadable module stuff */
152 #ifdef COMPILE_DL_WDDX
153 ZEND_GET_MODULE(wddx
)
154 #endif /* COMPILE_DL_WDDX */
157 /* {{{ wddx_module_entry
159 zend_module_entry wddx_module_entry
= {
160 STANDARD_MODULE_HEADER
,
169 STANDARD_MODULE_PROPERTIES
173 /* {{{ wddx_stack_init
175 static int wddx_stack_init(wddx_stack
*stack
)
178 stack
->elements
= (void **) safe_emalloc(sizeof(void **), STACK_BLOCK_SIZE
, 0);
179 stack
->max
= STACK_BLOCK_SIZE
;
180 stack
->varname
= NULL
;
187 /* {{{ wddx_stack_push
189 static int wddx_stack_push(wddx_stack
*stack
, void *element
, int size
)
191 if (stack
->top
>= stack
->max
) { /* we need to allocate more memory */
192 stack
->elements
= (void **) erealloc(stack
->elements
,
193 (sizeof(void **) * (stack
->max
+= STACK_BLOCK_SIZE
)));
195 stack
->elements
[stack
->top
] = (void *) emalloc(size
);
196 memcpy(stack
->elements
[stack
->top
], element
, size
);
201 /* {{{ wddx_stack_top
203 static int wddx_stack_top(wddx_stack
*stack
, void **element
)
205 if (stack
->top
> 0) {
206 *element
= stack
->elements
[stack
->top
- 1];
215 /* {{{ wddx_stack_is_empty
217 static int wddx_stack_is_empty(wddx_stack
*stack
)
219 if (stack
->top
== 0) {
227 /* {{{ wddx_stack_destroy
229 static int wddx_stack_destroy(wddx_stack
*stack
)
233 if (stack
->elements
) {
234 for (i
= 0; i
< stack
->top
; i
++) {
235 if (((st_entry
*)stack
->elements
[i
])->data
) {
236 zval_ptr_dtor(&((st_entry
*)stack
->elements
[i
])->data
);
238 if (((st_entry
*)stack
->elements
[i
])->varname
) {
239 efree(((st_entry
*)stack
->elements
[i
])->varname
);
241 efree(stack
->elements
[i
]);
243 efree(stack
->elements
);
249 /* {{{ release_wddx_packet_rsrc
251 static void release_wddx_packet_rsrc(zend_rsrc_list_entry
*rsrc TSRMLS_DC
)
253 smart_str
*str
= (smart_str
*)rsrc
->ptr
;
259 #include "ext/session/php_session.h"
261 #if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
262 /* {{{ PS_SERIALIZER_ENCODE_FUNC
264 PS_SERIALIZER_ENCODE_FUNC(wddx
)
269 packet
= php_wddx_constructor();
271 php_wddx_packet_start(packet
, NULL
, 0);
272 php_wddx_add_chunk_static(packet
, WDDX_STRUCT_S
);
275 php_wddx_serialize_var(packet
, *struc
, key
, key_length TSRMLS_CC
);
278 php_wddx_add_chunk_static(packet
, WDDX_STRUCT_E
);
279 php_wddx_packet_end(packet
);
280 *newstr
= php_wddx_gather(packet
);
281 php_wddx_destructor(packet
);
284 *newlen
= strlen(*newstr
);
291 /* {{{ PS_SERIALIZER_DECODE_FUNC
293 PS_SERIALIZER_DECODE_FUNC(wddx
)
308 MAKE_STD_ZVAL(retval
);
310 if ((ret
= php_wddx_deserialize_ex((char *)val
, vallen
, retval
)) == SUCCESS
) {
312 for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(retval
));
313 zend_hash_get_current_data(Z_ARRVAL_P(retval
), (void **) &ent
) == SUCCESS
;
314 zend_hash_move_forward(Z_ARRVAL_P(retval
))) {
315 hash_type
= zend_hash_get_current_key_ex(Z_ARRVAL_P(retval
), &key
, &key_length
, &idx
, 0, NULL
);
318 case HASH_KEY_IS_LONG
:
319 key_length
= slprintf(tmp
, sizeof(tmp
), "%ld", idx
) + 1;
322 case HASH_KEY_IS_STRING
:
323 php_set_session_var(key
, key_length
-1, *ent
, NULL TSRMLS_CC
);
329 zval_ptr_dtor(&retval
);
336 /* {{{ PHP_MINIT_FUNCTION
338 PHP_MINIT_FUNCTION(wddx
)
340 le_wddx
= zend_register_list_destructors_ex(release_wddx_packet_rsrc
, NULL
, "wddx", module_number
);
342 #if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
343 php_session_register_serializer("wddx",
344 PS_SERIALIZER_ENCODE_NAME(wddx
),
345 PS_SERIALIZER_DECODE_NAME(wddx
));
352 /* {{{ PHP_MINFO_FUNCTION
354 PHP_MINFO_FUNCTION(wddx
)
356 php_info_print_table_start();
357 #if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
358 php_info_print_table_header(2, "WDDX Support", "enabled" );
359 php_info_print_table_row(2, "WDDX Session Serializer", "enabled" );
361 php_info_print_table_row(2, "WDDX Support", "enabled" );
363 php_info_print_table_end();
367 /* {{{ php_wddx_packet_start
369 void php_wddx_packet_start(wddx_packet
*packet
, char *comment
, int comment_len
)
371 php_wddx_add_chunk_static(packet
, WDDX_PACKET_S
);
373 php_wddx_add_chunk_static(packet
, WDDX_HEADER_S
);
374 php_wddx_add_chunk_static(packet
, WDDX_COMMENT_S
);
375 php_wddx_add_chunk_ex(packet
, comment
, comment_len
);
376 php_wddx_add_chunk_static(packet
, WDDX_COMMENT_E
);
377 php_wddx_add_chunk_static(packet
, WDDX_HEADER_E
);
379 php_wddx_add_chunk_static(packet
, WDDX_HEADER
);
381 php_wddx_add_chunk_static(packet
, WDDX_DATA_S
);
385 /* {{{ php_wddx_packet_end
387 void php_wddx_packet_end(wddx_packet
*packet
)
389 php_wddx_add_chunk_static(packet
, WDDX_DATA_E
);
390 php_wddx_add_chunk_static(packet
, WDDX_PACKET_E
);
394 #define FLUSH_BUF() \
396 php_wddx_add_chunk_ex(packet, buf, l); \
400 /* {{{ php_wddx_serialize_string
402 static void php_wddx_serialize_string(wddx_packet
*packet
, zval
*var TSRMLS_DC
)
404 php_wddx_add_chunk_static(packet
, WDDX_STRING_S
);
406 if (Z_STRLEN_P(var
) > 0) {
410 buf
= php_escape_html_entities(Z_STRVAL_P(var
), Z_STRLEN_P(var
), &buf_len
, 0, ENT_QUOTES
, NULL TSRMLS_CC
);
412 php_wddx_add_chunk_ex(packet
, buf
, buf_len
);
416 php_wddx_add_chunk_static(packet
, WDDX_STRING_E
);
420 /* {{{ php_wddx_serialize_number
422 static void php_wddx_serialize_number(wddx_packet
*packet
, zval
*var
)
424 char tmp_buf
[WDDX_BUF_LEN
];
428 zval_copy_ctor(&tmp
);
429 convert_to_string(&tmp
);
430 snprintf(tmp_buf
, sizeof(tmp_buf
), WDDX_NUMBER
, Z_STRVAL(tmp
));
433 php_wddx_add_chunk(packet
, tmp_buf
);
437 /* {{{ php_wddx_serialize_boolean
439 static void php_wddx_serialize_boolean(wddx_packet
*packet
, zval
*var
)
441 php_wddx_add_chunk(packet
, Z_LVAL_P(var
) ? WDDX_BOOLEAN_TRUE
: WDDX_BOOLEAN_FALSE
);
445 /* {{{ php_wddx_serialize_unset
447 static void php_wddx_serialize_unset(wddx_packet
*packet
)
449 php_wddx_add_chunk_static(packet
, WDDX_NULL
);
453 /* {{{ php_wddx_serialize_object
455 static void php_wddx_serialize_object(wddx_packet
*packet
, zval
*obj
)
458 zval
**ent
, *fname
, **varname
;
462 char tmp_buf
[WDDX_BUF_LEN
];
463 HashTable
*objhash
, *sleephash
;
466 MAKE_STD_ZVAL(fname
);
467 ZVAL_STRING(fname
, "__sleep", 1);
470 * We try to call __sleep() method on object. It's supposed to return an
471 * array of property names to be serialized.
473 if (call_user_function_ex(CG(function_table
), &obj
, fname
, &retval
, 0, 0, 1, NULL TSRMLS_CC
) == SUCCESS
) {
474 if (retval
&& (sleephash
= HASH_OF(retval
))) {
475 PHP_CLASS_ATTRIBUTES
;
477 PHP_SET_CLASS_ATTRIBUTES(obj
);
479 php_wddx_add_chunk_static(packet
, WDDX_STRUCT_S
);
480 snprintf(tmp_buf
, WDDX_BUF_LEN
, WDDX_VAR_S
, PHP_CLASS_NAME_VAR
);
481 php_wddx_add_chunk(packet
, tmp_buf
);
482 php_wddx_add_chunk_static(packet
, WDDX_STRING_S
);
483 php_wddx_add_chunk_ex(packet
, class_name
, name_len
);
484 php_wddx_add_chunk_static(packet
, WDDX_STRING_E
);
485 php_wddx_add_chunk_static(packet
, WDDX_VAR_E
);
487 PHP_CLEANUP_CLASS_ATTRIBUTES();
489 objhash
= HASH_OF(obj
);
491 for (zend_hash_internal_pointer_reset(sleephash
);
492 zend_hash_get_current_data(sleephash
, (void **)&varname
) == SUCCESS
;
493 zend_hash_move_forward(sleephash
)) {
494 if (Z_TYPE_PP(varname
) != IS_STRING
) {
495 php_error_docref(NULL TSRMLS_CC
, E_NOTICE
, "__sleep should return an array only containing the names of instance-variables to serialize.");
499 if (zend_hash_find(objhash
, Z_STRVAL_PP(varname
), Z_STRLEN_PP(varname
)+1, (void **)&ent
) == SUCCESS
) {
500 php_wddx_serialize_var(packet
, *ent
, Z_STRVAL_PP(varname
), Z_STRLEN_PP(varname
) TSRMLS_CC
);
504 php_wddx_add_chunk_static(packet
, WDDX_STRUCT_E
);
509 PHP_CLASS_ATTRIBUTES
;
511 PHP_SET_CLASS_ATTRIBUTES(obj
);
513 php_wddx_add_chunk_static(packet
, WDDX_STRUCT_S
);
514 snprintf(tmp_buf
, WDDX_BUF_LEN
, WDDX_VAR_S
, PHP_CLASS_NAME_VAR
);
515 php_wddx_add_chunk(packet
, tmp_buf
);
516 php_wddx_add_chunk_static(packet
, WDDX_STRING_S
);
517 php_wddx_add_chunk_ex(packet
, class_name
, name_len
);
518 php_wddx_add_chunk_static(packet
, WDDX_STRING_E
);
519 php_wddx_add_chunk_static(packet
, WDDX_VAR_E
);
521 PHP_CLEANUP_CLASS_ATTRIBUTES();
523 objhash
= HASH_OF(obj
);
524 for (zend_hash_internal_pointer_reset(objhash
);
525 zend_hash_get_current_data(objhash
, (void**)&ent
) == SUCCESS
;
526 zend_hash_move_forward(objhash
)) {
531 if (zend_hash_get_current_key_ex(objhash
, &key
, &key_len
, &idx
, 0, NULL
) == HASH_KEY_IS_STRING
) {
532 const char *class_name
, *prop_name
;
534 zend_unmangle_property_name(key
, key_len
-1, &class_name
, &prop_name
);
535 php_wddx_serialize_var(packet
, *ent
, prop_name
, strlen(prop_name
)+1 TSRMLS_CC
);
537 key_len
= slprintf(tmp_buf
, sizeof(tmp_buf
), "%ld", idx
);
538 php_wddx_serialize_var(packet
, *ent
, tmp_buf
, key_len TSRMLS_CC
);
541 php_wddx_add_chunk_static(packet
, WDDX_STRUCT_E
);
548 zval_ptr_dtor(&retval
);
553 /* {{{ php_wddx_serialize_array
555 static void php_wddx_serialize_array(wddx_packet
*packet
, zval
*arr
)
560 int is_struct
= 0, ent_type
;
562 HashTable
*target_hash
;
563 char tmp_buf
[WDDX_BUF_LEN
];
568 target_hash
= HASH_OF(arr
);
570 for (zend_hash_internal_pointer_reset(target_hash
);
571 zend_hash_get_current_data(target_hash
, (void**)&ent
) == SUCCESS
;
572 zend_hash_move_forward(target_hash
)) {
574 type
= zend_hash_get_current_key(target_hash
, &key
, &idx
, 0);
576 if (type
== HASH_KEY_IS_STRING
) {
590 php_wddx_add_chunk_static(packet
, WDDX_STRUCT_S
);
592 snprintf(tmp_buf
, sizeof(tmp_buf
), WDDX_ARRAY_S
, zend_hash_num_elements(target_hash
));
593 php_wddx_add_chunk(packet
, tmp_buf
);
596 for (zend_hash_internal_pointer_reset(target_hash
);
597 zend_hash_get_current_data(target_hash
, (void**)&ent
) == SUCCESS
;
598 zend_hash_move_forward(target_hash
)) {
604 ent_type
= zend_hash_get_current_key_ex(target_hash
, &key
, &key_len
, &idx
, 0, NULL
);
606 if (ent_type
== HASH_KEY_IS_STRING
) {
607 php_wddx_serialize_var(packet
, *ent
, key
, key_len TSRMLS_CC
);
609 key_len
= slprintf(tmp_buf
, sizeof(tmp_buf
), "%ld", idx
);
610 php_wddx_serialize_var(packet
, *ent
, tmp_buf
, key_len TSRMLS_CC
);
613 php_wddx_serialize_var(packet
, *ent
, NULL
, 0 TSRMLS_CC
);
618 php_wddx_add_chunk_static(packet
, WDDX_STRUCT_E
);
620 php_wddx_add_chunk_static(packet
, WDDX_ARRAY_E
);
625 /* {{{ php_wddx_serialize_var
627 void php_wddx_serialize_var(wddx_packet
*packet
, zval
*var
, char *name
, int name_len TSRMLS_DC
)
635 name_esc
= php_escape_html_entities(name
, name_len
, &name_esc_len
, 0, ENT_QUOTES
, NULL TSRMLS_CC
);
636 tmp_buf
= emalloc(name_esc_len
+ sizeof(WDDX_VAR_S
));
637 snprintf(tmp_buf
, name_esc_len
+ sizeof(WDDX_VAR_S
), WDDX_VAR_S
, name_esc
);
638 php_wddx_add_chunk(packet
, tmp_buf
);
643 switch(Z_TYPE_P(var
)) {
645 php_wddx_serialize_string(packet
, var TSRMLS_CC
);
650 php_wddx_serialize_number(packet
, var
);
654 php_wddx_serialize_boolean(packet
, var
);
658 php_wddx_serialize_unset(packet
);
662 ht
= Z_ARRVAL_P(var
);
663 if (ht
->nApplyCount
> 1) {
664 php_error_docref(NULL TSRMLS_CC
, E_RECOVERABLE_ERROR
, "WDDX doesn't support circular references");
668 php_wddx_serialize_array(packet
, var
);
673 ht
= Z_OBJPROP_P(var
);
674 if (ht
->nApplyCount
> 1) {
675 php_error_docref(NULL TSRMLS_CC
, E_RECOVERABLE_ERROR
, "WDDX doesn't support circular references");
679 php_wddx_serialize_object(packet
, var
);
685 php_wddx_add_chunk_static(packet
, WDDX_VAR_E
);
690 /* {{{ php_wddx_add_var
692 static void php_wddx_add_var(wddx_packet
*packet
, zval
*name_var
)
695 HashTable
*target_hash
;
698 if (Z_TYPE_P(name_var
) == IS_STRING
) {
699 if (!EG(active_symbol_table
)) {
700 zend_rebuild_symbol_table(TSRMLS_C
);
702 if (zend_hash_find(EG(active_symbol_table
), Z_STRVAL_P(name_var
),
703 Z_STRLEN_P(name_var
)+1, (void**)&val
) != FAILURE
) {
704 php_wddx_serialize_var(packet
, *val
, Z_STRVAL_P(name_var
), Z_STRLEN_P(name_var
) TSRMLS_CC
);
706 } else if (Z_TYPE_P(name_var
) == IS_ARRAY
|| Z_TYPE_P(name_var
) == IS_OBJECT
) {
707 int is_array
= Z_TYPE_P(name_var
) == IS_ARRAY
;
709 target_hash
= HASH_OF(name_var
);
711 if (is_array
&& target_hash
->nApplyCount
> 1) {
712 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "recursion detected");
716 zend_hash_internal_pointer_reset(target_hash
);
718 while(zend_hash_get_current_data(target_hash
, (void**)&val
) == SUCCESS
) {
720 target_hash
->nApplyCount
++;
723 php_wddx_add_var(packet
, *val
);
726 target_hash
->nApplyCount
--;
728 zend_hash_move_forward(target_hash
);
734 /* {{{ php_wddx_push_element
736 static void php_wddx_push_element(void *user_data
, const XML_Char
*name
, const XML_Char
**atts
)
739 wddx_stack
*stack
= (wddx_stack
*)user_data
;
741 if (!strcmp(name
, EL_PACKET
)) {
744 if (atts
) for (i
=0; atts
[i
]; i
++) {
745 if (!strcmp(atts
[i
], EL_VERSION
)) {
746 /* nothing for now */
749 } else if (!strcmp(name
, EL_STRING
)) {
750 ent
.type
= ST_STRING
;
753 ALLOC_ZVAL(ent
.data
);
754 INIT_PZVAL(ent
.data
);
755 Z_TYPE_P(ent
.data
) = IS_STRING
;
756 Z_STRVAL_P(ent
.data
) = STR_EMPTY_ALLOC();
757 Z_STRLEN_P(ent
.data
) = 0;
758 wddx_stack_push((wddx_stack
*)stack
, &ent
, sizeof(st_entry
));
759 } else if (!strcmp(name
, EL_BINARY
)) {
760 ent
.type
= ST_BINARY
;
763 ALLOC_ZVAL(ent
.data
);
764 INIT_PZVAL(ent
.data
);
765 Z_TYPE_P(ent
.data
) = IS_STRING
;
766 Z_STRVAL_P(ent
.data
) = STR_EMPTY_ALLOC();
767 Z_STRLEN_P(ent
.data
) = 0;
768 wddx_stack_push((wddx_stack
*)stack
, &ent
, sizeof(st_entry
));
769 } else if (!strcmp(name
, EL_CHAR
)) {
772 if (atts
) for (i
= 0; atts
[i
]; i
++) {
773 if (!strcmp(atts
[i
], EL_CHAR_CODE
) && atts
[++i
] && atts
[i
][0]) {
776 snprintf(tmp_buf
, sizeof(tmp_buf
), "%c", (char)strtol(atts
[i
], NULL
, 16));
777 php_wddx_process_data(user_data
, tmp_buf
, strlen(tmp_buf
));
781 } else if (!strcmp(name
, EL_NUMBER
)) {
782 ent
.type
= ST_NUMBER
;
785 ALLOC_ZVAL(ent
.data
);
786 INIT_PZVAL(ent
.data
);
787 Z_TYPE_P(ent
.data
) = IS_LONG
;
788 Z_LVAL_P(ent
.data
) = 0;
789 wddx_stack_push((wddx_stack
*)stack
, &ent
, sizeof(st_entry
));
790 } else if (!strcmp(name
, EL_BOOLEAN
)) {
793 if (atts
) for (i
= 0; atts
[i
]; i
++) {
794 if (!strcmp(atts
[i
], EL_VALUE
) && atts
[++i
] && atts
[i
][0]) {
795 ent
.type
= ST_BOOLEAN
;
798 ALLOC_ZVAL(ent
.data
);
799 INIT_PZVAL(ent
.data
);
800 Z_TYPE_P(ent
.data
) = IS_BOOL
;
801 wddx_stack_push((wddx_stack
*)stack
, &ent
, sizeof(st_entry
));
802 php_wddx_process_data(user_data
, atts
[i
], strlen(atts
[i
]));
806 } else if (!strcmp(name
, EL_NULL
)) {
810 ALLOC_ZVAL(ent
.data
);
811 INIT_PZVAL(ent
.data
);
814 wddx_stack_push((wddx_stack
*)stack
, &ent
, sizeof(st_entry
));
815 } else if (!strcmp(name
, EL_ARRAY
)) {
819 ALLOC_ZVAL(ent
.data
);
820 array_init(ent
.data
);
821 INIT_PZVAL(ent
.data
);
822 wddx_stack_push((wddx_stack
*)stack
, &ent
, sizeof(st_entry
));
823 } else if (!strcmp(name
, EL_STRUCT
)) {
824 ent
.type
= ST_STRUCT
;
827 ALLOC_ZVAL(ent
.data
);
828 array_init(ent
.data
);
829 INIT_PZVAL(ent
.data
);
830 wddx_stack_push((wddx_stack
*)stack
, &ent
, sizeof(st_entry
));
831 } else if (!strcmp(name
, EL_VAR
)) {
834 if (atts
) for (i
= 0; atts
[i
]; i
++) {
835 if (!strcmp(atts
[i
], EL_NAME
) && atts
[++i
] && atts
[i
][0]) {
836 stack
->varname
= estrdup(atts
[i
]);
840 } else if (!strcmp(name
, EL_RECORDSET
)) {
843 ent
.type
= ST_RECORDSET
;
845 MAKE_STD_ZVAL(ent
.data
);
846 array_init(ent
.data
);
848 if (atts
) for (i
= 0; atts
[i
]; i
++) {
849 if (!strcmp(atts
[i
], "fieldNames") && atts
[++i
] && atts
[i
][0]) {
852 char *p1
, *p2
, *endp
;
854 endp
= (char *)atts
[i
] + strlen(atts
[i
]);
855 p1
= (char *)atts
[i
];
856 while ((p2
= php_memnstr(p1
, ",", sizeof(",")-1, endp
)) != NULL
) {
857 key
= estrndup(p1
, p2
- p1
);
860 add_assoc_zval_ex(ent
.data
, key
, p2
- p1
+ 1, tmp
);
861 p1
= p2
+ sizeof(",")-1;
868 add_assoc_zval_ex(ent
.data
, p1
, endp
- p1
+ 1, tmp
);
875 wddx_stack_push((wddx_stack
*)stack
, &ent
, sizeof(st_entry
));
876 } else if (!strcmp(name
, EL_FIELD
)) {
884 if (atts
) for (i
= 0; atts
[i
]; i
++) {
885 if (!strcmp(atts
[i
], EL_NAME
) && atts
[++i
] && atts
[i
][0]) {
889 if (wddx_stack_top(stack
, (void**)&recordset
) == SUCCESS
&&
890 recordset
->type
== ST_RECORDSET
&&
891 zend_hash_find(Z_ARRVAL_P(recordset
->data
), (char*)atts
[i
], strlen(atts
[i
])+1, (void**)&field
) == SUCCESS
) {
899 wddx_stack_push((wddx_stack
*)stack
, &ent
, sizeof(st_entry
));
900 } else if (!strcmp(name
, EL_DATETIME
)) {
901 ent
.type
= ST_DATETIME
;
904 ALLOC_ZVAL(ent
.data
);
905 INIT_PZVAL(ent
.data
);
906 Z_TYPE_P(ent
.data
) = IS_LONG
;
907 wddx_stack_push((wddx_stack
*)stack
, &ent
, sizeof(st_entry
));
912 /* {{{ php_wddx_pop_element
914 static void php_wddx_pop_element(void *user_data
, const XML_Char
*name
)
916 st_entry
*ent1
, *ent2
;
917 wddx_stack
*stack
= (wddx_stack
*)user_data
;
918 HashTable
*target_hash
;
919 zend_class_entry
**pce
;
925 if (stack
->top
== 0) {
929 if (!strcmp(name
, EL_STRING
) || !strcmp(name
, EL_NUMBER
) ||
930 !strcmp(name
, EL_BOOLEAN
) || !strcmp(name
, EL_NULL
) ||
931 !strcmp(name
, EL_ARRAY
) || !strcmp(name
, EL_STRUCT
) ||
932 !strcmp(name
, EL_RECORDSET
) || !strcmp(name
, EL_BINARY
) ||
933 !strcmp(name
, EL_DATETIME
)) {
934 wddx_stack_top(stack
, (void**)&ent1
);
936 if (!strcmp(name
, EL_BINARY
)) {
938 unsigned char *new_str
;
940 new_str
= php_base64_decode(Z_STRVAL_P(ent1
->data
), Z_STRLEN_P(ent1
->data
), &new_len
);
941 STR_FREE(Z_STRVAL_P(ent1
->data
));
942 Z_STRVAL_P(ent1
->data
) = new_str
;
943 Z_STRLEN_P(ent1
->data
) = new_len
;
946 /* Call __wakeup() method on the object. */
947 if (Z_TYPE_P(ent1
->data
) == IS_OBJECT
) {
948 zval
*fname
, *retval
= NULL
;
950 MAKE_STD_ZVAL(fname
);
951 ZVAL_STRING(fname
, "__wakeup", 1);
953 call_user_function_ex(NULL
, &ent1
->data
, fname
, &retval
, 0, 0, 0, NULL TSRMLS_CC
);
958 zval_ptr_dtor(&retval
);
962 if (stack
->top
> 1) {
964 wddx_stack_top(stack
, (void**)&ent2
);
966 /* if non-existent field */
967 if (ent2
->type
== ST_FIELD
&& ent2
->data
== NULL
) {
968 zval_ptr_dtor(&ent1
->data
);
973 if (Z_TYPE_P(ent2
->data
) == IS_ARRAY
|| Z_TYPE_P(ent2
->data
) == IS_OBJECT
) {
974 target_hash
= HASH_OF(ent2
->data
);
977 if (!strcmp(ent1
->varname
, PHP_CLASS_NAME_VAR
) &&
978 Z_TYPE_P(ent1
->data
) == IS_STRING
&& Z_STRLEN_P(ent1
->data
)) {
979 zend_bool incomplete_class
= 0;
981 zend_str_tolower(Z_STRVAL_P(ent1
->data
), Z_STRLEN_P(ent1
->data
));
982 if (zend_hash_find(EG(class_table
), Z_STRVAL_P(ent1
->data
),
983 Z_STRLEN_P(ent1
->data
)+1, (void **) &pce
)==FAILURE
) {
984 incomplete_class
= 1;
988 /* Initialize target object */
990 object_init_ex(obj
, *pce
);
992 /* Merge current hashtable with object's default properties */
993 zend_hash_merge(Z_OBJPROP_P(obj
),
994 Z_ARRVAL_P(ent2
->data
),
995 (void (*)(void *)) zval_add_ref
,
996 (void *) &tmp
, sizeof(zval
*), 0);
998 if (incomplete_class
) {
999 php_store_class_name(obj
, Z_STRVAL_P(ent1
->data
), Z_STRLEN_P(ent1
->data
));
1002 /* Clean up old array entry */
1003 zval_ptr_dtor(&ent2
->data
);
1005 /* Set stack entry to point to the newly created object */
1008 /* Clean up class name var entry */
1009 zval_ptr_dtor(&ent1
->data
);
1010 } else if (Z_TYPE_P(ent2
->data
) == IS_OBJECT
) {
1011 zend_class_entry
*old_scope
= EG(scope
);
1013 EG(scope
) = Z_OBJCE_P(ent2
->data
);
1014 Z_DELREF_P(ent1
->data
);
1015 add_property_zval(ent2
->data
, ent1
->varname
, ent1
->data
);
1016 EG(scope
) = old_scope
;
1018 zend_symtable_update(target_hash
, ent1
->varname
, strlen(ent1
->varname
)+1, &ent1
->data
, sizeof(zval
*), NULL
);
1020 efree(ent1
->varname
);
1022 zend_hash_next_index_insert(target_hash
, &ent1
->data
, sizeof(zval
*), NULL
);
1029 } else if (!strcmp(name
, EL_VAR
) && stack
->varname
) {
1030 efree(stack
->varname
);
1031 } else if (!strcmp(name
, EL_FIELD
)) {
1033 wddx_stack_top(stack
, (void **)&ent
);
1040 /* {{{ php_wddx_process_data
1042 static void php_wddx_process_data(void *user_data
, const XML_Char
*s
, int len
)
1045 wddx_stack
*stack
= (wddx_stack
*)user_data
;
1048 if (!wddx_stack_is_empty(stack
) && !stack
->done
) {
1049 wddx_stack_top(stack
, (void**)&ent
);
1050 switch (Z_TYPE_P(ent
)) {
1052 if (Z_STRLEN_P(ent
->data
) == 0) {
1053 STR_FREE(Z_STRVAL_P(ent
->data
));
1054 Z_STRVAL_P(ent
->data
) = estrndup(s
, len
);
1055 Z_STRLEN_P(ent
->data
) = len
;
1057 Z_STRVAL_P(ent
->data
) = erealloc(Z_STRVAL_P(ent
->data
), Z_STRLEN_P(ent
->data
) + len
+ 1);
1058 memcpy(Z_STRVAL_P(ent
->data
) + Z_STRLEN_P(ent
->data
), s
, len
);
1059 Z_STRLEN_P(ent
->data
) += len
;
1060 Z_STRVAL_P(ent
->data
)[Z_STRLEN_P(ent
->data
)] = '\0';
1065 if (Z_STRLEN_P(ent
->data
) == 0) {
1066 STR_FREE(Z_STRVAL_P(ent
->data
));
1067 Z_STRVAL_P(ent
->data
) = estrndup(s
, len
+ 1);
1069 Z_STRVAL_P(ent
->data
) = erealloc(Z_STRVAL_P(ent
->data
), Z_STRLEN_P(ent
->data
) + len
+ 1);
1070 memcpy(Z_STRVAL_P(ent
->data
) + Z_STRLEN_P(ent
->data
), s
, len
);
1072 Z_STRLEN_P(ent
->data
) += len
;
1073 Z_STRVAL_P(ent
->data
)[Z_STRLEN_P(ent
->data
)] = '\0';
1077 Z_TYPE_P(ent
->data
) = IS_STRING
;
1078 Z_STRLEN_P(ent
->data
) = len
;
1079 Z_STRVAL_P(ent
->data
) = estrndup(s
, len
);
1080 convert_scalar_to_number(ent
->data TSRMLS_CC
);
1084 if (!strcmp(s
, "true")) {
1085 Z_LVAL_P(ent
->data
) = 1;
1086 } else if (!strcmp(s
, "false")) {
1087 Z_LVAL_P(ent
->data
) = 0;
1090 zval_ptr_dtor(&ent
->data
);
1092 efree(ent
->varname
);
1100 tmp
= emalloc(len
+ 1);
1101 memcpy(tmp
, s
, len
);
1104 Z_LVAL_P(ent
->data
) = php_parse_date(tmp
, NULL
);
1105 /* date out of range < 1969 or > 2038 */
1106 if (Z_LVAL_P(ent
->data
) == -1) {
1107 Z_TYPE_P(ent
->data
) = IS_STRING
;
1108 Z_STRLEN_P(ent
->data
) = len
;
1109 Z_STRVAL_P(ent
->data
) = estrndup(s
, len
);
1122 /* {{{ php_wddx_deserialize_ex
1124 int php_wddx_deserialize_ex(char *value
, int vallen
, zval
*return_value
)
1131 wddx_stack_init(&stack
);
1132 parser
= XML_ParserCreate("UTF-8");
1134 XML_SetUserData(parser
, &stack
);
1135 XML_SetElementHandler(parser
, php_wddx_push_element
, php_wddx_pop_element
);
1136 XML_SetCharacterDataHandler(parser
, php_wddx_process_data
);
1138 XML_Parse(parser
, value
, vallen
, 1);
1140 XML_ParserFree(parser
);
1142 if (stack
.top
== 1) {
1143 wddx_stack_top(&stack
, (void**)&ent
);
1144 *return_value
= *(ent
->data
);
1145 zval_copy_ctor(return_value
);
1151 wddx_stack_destroy(&stack
);
1157 /* {{{ proto string wddx_serialize_value(mixed var [, string comment])
1158 Creates a new packet and serializes the given value */
1159 PHP_FUNCTION(wddx_serialize_value
)
1162 char *comment
= NULL
;
1163 int comment_len
= 0;
1164 wddx_packet
*packet
;
1166 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "z|s", &var
, &comment
, &comment_len
) == FAILURE
) {
1170 packet
= php_wddx_constructor();
1172 php_wddx_packet_start(packet
, comment
, comment_len
);
1173 php_wddx_serialize_var(packet
, var
, NULL
, 0 TSRMLS_CC
);
1174 php_wddx_packet_end(packet
);
1176 ZVAL_STRINGL(return_value
, packet
->c
, packet
->len
, 1);
1177 smart_str_free(packet
);
1182 /* {{{ proto string wddx_serialize_vars(mixed var_name [, mixed ...])
1183 Creates a new packet and serializes given variables into a struct */
1184 PHP_FUNCTION(wddx_serialize_vars
)
1187 wddx_packet
*packet
;
1188 zval
***args
= NULL
;
1190 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "+", &args
, &num_args
) == FAILURE
) {
1194 packet
= php_wddx_constructor();
1196 php_wddx_packet_start(packet
, NULL
, 0);
1197 php_wddx_add_chunk_static(packet
, WDDX_STRUCT_S
);
1199 for (i
=0; i
<num_args
; i
++) {
1200 if (Z_TYPE_PP(args
[i
]) != IS_ARRAY
&& Z_TYPE_PP(args
[i
]) != IS_OBJECT
) {
1201 convert_to_string_ex(args
[i
]);
1203 php_wddx_add_var(packet
, *args
[i
]);
1206 php_wddx_add_chunk_static(packet
, WDDX_STRUCT_E
);
1207 php_wddx_packet_end(packet
);
1211 ZVAL_STRINGL(return_value
, packet
->c
, packet
->len
, 1);
1212 smart_str_free(packet
);
1217 /* {{{ php_wddx_constructor
1219 wddx_packet
*php_wddx_constructor(void)
1223 packet
= (smart_str
*)emalloc(sizeof(smart_str
));
1230 /* {{{ php_wddx_destructor
1232 void php_wddx_destructor(wddx_packet
*packet
)
1234 smart_str_free(packet
);
1239 /* {{{ proto resource wddx_packet_start([string comment])
1240 Starts a WDDX packet with optional comment and returns the packet id */
1241 PHP_FUNCTION(wddx_packet_start
)
1243 char *comment
= NULL
;
1244 int comment_len
= 0;
1245 wddx_packet
*packet
;
1249 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|s", &comment
, &comment_len
) == FAILURE
) {
1253 packet
= php_wddx_constructor();
1255 php_wddx_packet_start(packet
, comment
, comment_len
);
1256 php_wddx_add_chunk_static(packet
, WDDX_STRUCT_S
);
1258 ZEND_REGISTER_RESOURCE(return_value
, packet
, le_wddx
);
1262 /* {{{ proto string wddx_packet_end(resource packet_id)
1263 Ends specified WDDX packet and returns the string containing the packet */
1264 PHP_FUNCTION(wddx_packet_end
)
1267 wddx_packet
*packet
= NULL
;
1269 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "r", &packet_id
) == FAILURE
) {
1273 ZEND_FETCH_RESOURCE(packet
, wddx_packet
*, &packet_id
, -1, "WDDX packet ID", le_wddx
);
1275 php_wddx_add_chunk_static(packet
, WDDX_STRUCT_E
);
1277 php_wddx_packet_end(packet
);
1279 ZVAL_STRINGL(return_value
, packet
->c
, packet
->len
, 1);
1281 zend_list_delete(Z_LVAL_P(packet_id
));
1285 /* {{{ proto int wddx_add_vars(resource packet_id, mixed var_names [, mixed ...])
1286 Serializes given variables and adds them to packet given by packet_id */
1287 PHP_FUNCTION(wddx_add_vars
)
1290 zval
***args
= NULL
;
1292 wddx_packet
*packet
= NULL
;
1294 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "r+", &packet_id
, &args
, &num_args
) == FAILURE
) {
1298 if (!ZEND_FETCH_RESOURCE_NO_RETURN(packet
, wddx_packet
*, &packet_id
, -1, "WDDX packet ID", le_wddx
)) {
1308 for (i
=0; i
<num_args
; i
++) {
1309 if (Z_TYPE_PP(args
[i
]) != IS_ARRAY
&& Z_TYPE_PP(args
[i
]) != IS_OBJECT
) {
1310 convert_to_string_ex(args
[i
]);
1312 php_wddx_add_var(packet
, (*args
[i
]));
1320 /* {{{ proto mixed wddx_deserialize(mixed packet)
1321 Deserializes given packet and returns a PHP value */
1322 PHP_FUNCTION(wddx_deserialize
)
1327 php_stream
*stream
= NULL
;
1329 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "z", &packet
) == FAILURE
) {
1333 if (Z_TYPE_P(packet
) == IS_STRING
) {
1334 payload
= Z_STRVAL_P(packet
);
1335 payload_len
= Z_STRLEN_P(packet
);
1336 } else if (Z_TYPE_P(packet
) == IS_RESOURCE
) {
1337 php_stream_from_zval(stream
, &packet
);
1339 payload_len
= php_stream_copy_to_mem(stream
, &payload
, PHP_STREAM_COPY_ALL
, 0);
1342 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Expecting parameter 1 to be a string or a stream");
1346 if (payload_len
== 0) {
1350 php_wddx_deserialize_ex(payload
, payload_len
, return_value
);
1358 #endif /* HAVE_LIBEXPAT */
1365 * vim600: sw=4 ts=4 fdm=marker
1366 * vim<600: sw=4 ts=4