This source file includes following definitions.
- wddx_stack_init
- wddx_stack_push
- wddx_stack_top
- wddx_stack_is_empty
- wddx_stack_destroy
- release_wddx_packet_rsrc
- PS_SERIALIZER_ENCODE_FUNC
- PS_SERIALIZER_DECODE_FUNC
- PHP_MINIT_FUNCTION
- PHP_MINFO_FUNCTION
- php_wddx_packet_start
- php_wddx_packet_end
- php_wddx_serialize_string
- php_wddx_serialize_number
- php_wddx_serialize_boolean
- php_wddx_serialize_unset
- php_wddx_serialize_object
- php_wddx_serialize_array
- php_wddx_serialize_var
- php_wddx_add_var
- php_wddx_push_element
- php_wddx_pop_element
- php_wddx_process_data
- php_wddx_deserialize_ex
- PHP_FUNCTION
- PHP_FUNCTION
- php_wddx_constructor
- php_wddx_destructor
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "php.h"
26
27 #if HAVE_WDDX
28
29 #include "ext/xml/expat_compat.h"
30 #include "php_wddx.h"
31 #include "php_wddx_api.h"
32
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"
43
44 #define WDDX_BUF_LEN 256
45 #define PHP_CLASS_NAME_VAR "php_class_name"
46
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"
58 #define EL_VAR "var"
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"
64
65 #define php_wddx_deserialize(a,b) \
66 php_wddx_deserialize_ex((a)->value.str.val, (a)->value.str.len, (b))
67
68 #define SET_STACK_VARNAME \
69 if (stack->varname) { \
70 ent.varname = estrdup(stack->varname); \
71 efree(stack->varname); \
72 stack->varname = NULL; \
73 } else \
74 ent.varname = NULL; \
75
76 static int le_wddx;
77
78 typedef struct {
79 zval *data;
80 enum {
81 ST_ARRAY,
82 ST_BOOLEAN,
83 ST_NULL,
84 ST_NUMBER,
85 ST_STRING,
86 ST_BINARY,
87 ST_STRUCT,
88 ST_RECORDSET,
89 ST_FIELD,
90 ST_DATETIME
91 } type;
92 char *varname;
93 } st_entry;
94
95 typedef struct {
96 int top, max;
97 char *varname;
98 zend_bool done;
99 void **elements;
100 } wddx_stack;
101
102
103 static void php_wddx_process_data(void *user_data, const XML_Char *s, int len);
104
105
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)
109 ZEND_END_ARG_INFO()
110
111 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_serialize_vars, 0, 0, 1)
112 ZEND_ARG_VARIADIC_INFO(0, var_names)
113 ZEND_END_ARG_INFO()
114
115 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_serialize_start, 0, 0, 0)
116 ZEND_ARG_INFO(0, comment)
117 ZEND_END_ARG_INFO()
118
119 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_packet_end, 0, 0, 1)
120 ZEND_ARG_INFO(0, packet_id)
121 ZEND_END_ARG_INFO()
122
123 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_add_vars, 0, 0, 2)
124 ZEND_ARG_INFO(0, packet_id)
125 ZEND_ARG_VARIADIC_INFO(0, var_names)
126 ZEND_END_ARG_INFO()
127
128 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_deserialize, 0, 0, 1)
129 ZEND_ARG_INFO(0, packet)
130 ZEND_END_ARG_INFO()
131
132
133
134
135 const zend_function_entry wddx_functions[] = {
136 PHP_FE(wddx_serialize_value, arginfo_wddx_serialize_value)
137 PHP_FE(wddx_serialize_vars, arginfo_wddx_serialize_vars)
138 PHP_FE(wddx_packet_start, arginfo_wddx_serialize_start)
139 PHP_FE(wddx_packet_end, arginfo_wddx_packet_end)
140 PHP_FE(wddx_add_vars, arginfo_wddx_add_vars)
141 PHP_FE(wddx_deserialize, arginfo_wddx_deserialize)
142 PHP_FE_END
143 };
144
145
146 PHP_MINIT_FUNCTION(wddx);
147 PHP_MINFO_FUNCTION(wddx);
148
149
150 #ifdef COMPILE_DL_WDDX
151 ZEND_GET_MODULE(wddx)
152 #endif
153
154
155
156
157 zend_module_entry wddx_module_entry = {
158 STANDARD_MODULE_HEADER,
159 "wddx",
160 wddx_functions,
161 PHP_MINIT(wddx),
162 NULL,
163 NULL,
164 NULL,
165 PHP_MINFO(wddx),
166 NO_VERSION_YET,
167 STANDARD_MODULE_PROPERTIES
168 };
169
170
171
172
173 static int wddx_stack_init(wddx_stack *stack)
174 {
175 stack->top = 0;
176 stack->elements = (void **) safe_emalloc(sizeof(void **), STACK_BLOCK_SIZE, 0);
177 stack->max = STACK_BLOCK_SIZE;
178 stack->varname = NULL;
179 stack->done = 0;
180
181 return SUCCESS;
182 }
183
184
185
186
187 static int wddx_stack_push(wddx_stack *stack, void *element, int size)
188 {
189 if (stack->top >= stack->max) {
190 stack->elements = (void **) erealloc(stack->elements,
191 (sizeof(void **) * (stack->max += STACK_BLOCK_SIZE)));
192 }
193 stack->elements[stack->top] = (void *) emalloc(size);
194 memcpy(stack->elements[stack->top], element, size);
195 return stack->top++;
196 }
197
198
199
200
201 static int wddx_stack_top(wddx_stack *stack, void **element)
202 {
203 if (stack->top > 0) {
204 *element = stack->elements[stack->top - 1];
205 return SUCCESS;
206 } else {
207 *element = NULL;
208 return FAILURE;
209 }
210 }
211
212
213
214
215 static int wddx_stack_is_empty(wddx_stack *stack)
216 {
217 if (stack->top == 0) {
218 return 1;
219 } else {
220 return 0;
221 }
222 }
223
224
225
226
227 static int wddx_stack_destroy(wddx_stack *stack)
228 {
229 register int i;
230
231 if (stack->elements) {
232 for (i = 0; i < stack->top; i++) {
233 if (((st_entry *)stack->elements[i])->data) {
234 zval_ptr_dtor(&((st_entry *)stack->elements[i])->data);
235 }
236 if (((st_entry *)stack->elements[i])->varname) {
237 efree(((st_entry *)stack->elements[i])->varname);
238 }
239 efree(stack->elements[i]);
240 }
241 efree(stack->elements);
242 }
243 return SUCCESS;
244 }
245
246
247
248
249 static void release_wddx_packet_rsrc(zend_rsrc_list_entry *rsrc TSRMLS_DC)
250 {
251 smart_str *str = (smart_str *)rsrc->ptr;
252 smart_str_free(str);
253 efree(str);
254 }
255
256
257 #include "ext/session/php_session.h"
258
259 #if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
260
261
262 PS_SERIALIZER_ENCODE_FUNC(wddx)
263 {
264 wddx_packet *packet;
265 PS_ENCODE_VARS;
266
267 packet = php_wddx_constructor();
268
269 php_wddx_packet_start(packet, NULL, 0);
270 php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
271
272 PS_ENCODE_LOOP(
273 php_wddx_serialize_var(packet, *struc, key, key_length TSRMLS_CC);
274 );
275
276 php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
277 php_wddx_packet_end(packet);
278 *newstr = php_wddx_gather(packet);
279 php_wddx_destructor(packet);
280
281 if (newlen) {
282 *newlen = strlen(*newstr);
283 }
284
285 return SUCCESS;
286 }
287
288
289
290
291 PS_SERIALIZER_DECODE_FUNC(wddx)
292 {
293 zval *retval;
294 zval **ent;
295 char *key;
296 uint key_length;
297 char tmp[128];
298 ulong idx;
299 int hash_type;
300 int ret;
301
302 if (vallen == 0) {
303 return SUCCESS;
304 }
305
306 MAKE_STD_ZVAL(retval);
307
308 if ((ret = php_wddx_deserialize_ex((char *)val, vallen, retval)) == SUCCESS) {
309 if (Z_TYPE_P(retval) != IS_ARRAY) {
310 zval_ptr_dtor(&retval);
311 return FAILURE;
312 }
313 for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(retval));
314 zend_hash_get_current_data(Z_ARRVAL_P(retval), (void **) &ent) == SUCCESS;
315 zend_hash_move_forward(Z_ARRVAL_P(retval))) {
316 hash_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(retval), &key, &key_length, &idx, 0, NULL);
317
318 switch (hash_type) {
319 case HASH_KEY_IS_LONG:
320 key_length = slprintf(tmp, sizeof(tmp), "%ld", idx) + 1;
321 key = tmp;
322
323 case HASH_KEY_IS_STRING:
324 php_set_session_var(key, key_length-1, *ent, NULL TSRMLS_CC);
325 PS_ADD_VAR(key);
326 }
327 }
328 }
329
330 zval_ptr_dtor(&retval);
331
332 return ret;
333 }
334
335 #endif
336
337
338
339 PHP_MINIT_FUNCTION(wddx)
340 {
341 le_wddx = zend_register_list_destructors_ex(release_wddx_packet_rsrc, NULL, "wddx", module_number);
342
343 #if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
344 php_session_register_serializer("wddx",
345 PS_SERIALIZER_ENCODE_NAME(wddx),
346 PS_SERIALIZER_DECODE_NAME(wddx));
347 #endif
348
349 return SUCCESS;
350 }
351
352
353
354
355 PHP_MINFO_FUNCTION(wddx)
356 {
357 php_info_print_table_start();
358 #if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
359 php_info_print_table_header(2, "WDDX Support", "enabled" );
360 php_info_print_table_row(2, "WDDX Session Serializer", "enabled" );
361 #else
362 php_info_print_table_row(2, "WDDX Support", "enabled" );
363 #endif
364 php_info_print_table_end();
365 }
366
367
368
369
370 void php_wddx_packet_start(wddx_packet *packet, char *comment, int comment_len)
371 {
372 php_wddx_add_chunk_static(packet, WDDX_PACKET_S);
373 if (comment) {
374 php_wddx_add_chunk_static(packet, WDDX_HEADER_S);
375 php_wddx_add_chunk_static(packet, WDDX_COMMENT_S);
376 php_wddx_add_chunk_ex(packet, comment, comment_len);
377 php_wddx_add_chunk_static(packet, WDDX_COMMENT_E);
378 php_wddx_add_chunk_static(packet, WDDX_HEADER_E);
379 } else {
380 php_wddx_add_chunk_static(packet, WDDX_HEADER);
381 }
382 php_wddx_add_chunk_static(packet, WDDX_DATA_S);
383 }
384
385
386
387
388 void php_wddx_packet_end(wddx_packet *packet)
389 {
390 php_wddx_add_chunk_static(packet, WDDX_DATA_E);
391 php_wddx_add_chunk_static(packet, WDDX_PACKET_E);
392 }
393
394
395 #define FLUSH_BUF() \
396 if (l > 0) { \
397 php_wddx_add_chunk_ex(packet, buf, l); \
398 l = 0; \
399 }
400
401
402
403 static void php_wddx_serialize_string(wddx_packet *packet, zval *var TSRMLS_DC)
404 {
405 php_wddx_add_chunk_static(packet, WDDX_STRING_S);
406
407 if (Z_STRLEN_P(var) > 0) {
408 char *buf;
409 size_t buf_len;
410
411 buf = php_escape_html_entities(Z_STRVAL_P(var), Z_STRLEN_P(var), &buf_len, 0, ENT_QUOTES, NULL TSRMLS_CC);
412
413 php_wddx_add_chunk_ex(packet, buf, buf_len);
414
415 str_efree(buf);
416 }
417 php_wddx_add_chunk_static(packet, WDDX_STRING_E);
418 }
419
420
421
422
423 static void php_wddx_serialize_number(wddx_packet *packet, zval *var)
424 {
425 char tmp_buf[WDDX_BUF_LEN];
426 zval tmp;
427
428 tmp = *var;
429 zval_copy_ctor(&tmp);
430 convert_to_string(&tmp);
431 snprintf(tmp_buf, sizeof(tmp_buf), WDDX_NUMBER, Z_STRVAL(tmp));
432 zval_dtor(&tmp);
433
434 php_wddx_add_chunk(packet, tmp_buf);
435 }
436
437
438
439
440 static void php_wddx_serialize_boolean(wddx_packet *packet, zval *var)
441 {
442 php_wddx_add_chunk(packet, Z_LVAL_P(var) ? WDDX_BOOLEAN_TRUE : WDDX_BOOLEAN_FALSE);
443 }
444
445
446
447
448 static void php_wddx_serialize_unset(wddx_packet *packet)
449 {
450 php_wddx_add_chunk_static(packet, WDDX_NULL);
451 }
452
453
454
455
456 static void php_wddx_serialize_object(wddx_packet *packet, zval *obj)
457 {
458
459 zval **ent, *fname, **varname;
460 zval *retval = NULL;
461 const char *key;
462 ulong idx;
463 char tmp_buf[WDDX_BUF_LEN];
464 HashTable *objhash, *sleephash;
465 TSRMLS_FETCH();
466
467 MAKE_STD_ZVAL(fname);
468 ZVAL_STRING(fname, "__sleep", 1);
469
470
471
472
473
474 if (call_user_function_ex(CG(function_table), &obj, fname, &retval, 0, 0, 1, NULL TSRMLS_CC) == SUCCESS) {
475 if (retval && (sleephash = HASH_OF(retval))) {
476 PHP_CLASS_ATTRIBUTES;
477
478 PHP_SET_CLASS_ATTRIBUTES(obj);
479
480 php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
481 snprintf(tmp_buf, WDDX_BUF_LEN, WDDX_VAR_S, PHP_CLASS_NAME_VAR);
482 php_wddx_add_chunk(packet, tmp_buf);
483 php_wddx_add_chunk_static(packet, WDDX_STRING_S);
484 php_wddx_add_chunk_ex(packet, class_name, name_len);
485 php_wddx_add_chunk_static(packet, WDDX_STRING_E);
486 php_wddx_add_chunk_static(packet, WDDX_VAR_E);
487
488 PHP_CLEANUP_CLASS_ATTRIBUTES();
489
490 objhash = HASH_OF(obj);
491
492 for (zend_hash_internal_pointer_reset(sleephash);
493 zend_hash_get_current_data(sleephash, (void **)&varname) == SUCCESS;
494 zend_hash_move_forward(sleephash)) {
495 if (Z_TYPE_PP(varname) != IS_STRING) {
496 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "__sleep should return an array only containing the names of instance-variables to serialize.");
497 continue;
498 }
499
500 if (zend_hash_find(objhash, Z_STRVAL_PP(varname), Z_STRLEN_PP(varname)+1, (void **)&ent) == SUCCESS) {
501 php_wddx_serialize_var(packet, *ent, Z_STRVAL_PP(varname), Z_STRLEN_PP(varname) TSRMLS_CC);
502 }
503 }
504
505 php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
506 }
507 } else {
508 uint key_len;
509
510 PHP_CLASS_ATTRIBUTES;
511
512 PHP_SET_CLASS_ATTRIBUTES(obj);
513
514 php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
515 snprintf(tmp_buf, WDDX_BUF_LEN, WDDX_VAR_S, PHP_CLASS_NAME_VAR);
516 php_wddx_add_chunk(packet, tmp_buf);
517 php_wddx_add_chunk_static(packet, WDDX_STRING_S);
518 php_wddx_add_chunk_ex(packet, class_name, name_len);
519 php_wddx_add_chunk_static(packet, WDDX_STRING_E);
520 php_wddx_add_chunk_static(packet, WDDX_VAR_E);
521
522 PHP_CLEANUP_CLASS_ATTRIBUTES();
523
524 objhash = HASH_OF(obj);
525 for (zend_hash_internal_pointer_reset(objhash);
526 zend_hash_get_current_data(objhash, (void**)&ent) == SUCCESS;
527 zend_hash_move_forward(objhash)) {
528 if (*ent == obj) {
529 continue;
530 }
531
532 if (zend_hash_get_current_key_ex(objhash, &key, &key_len, &idx, 0, NULL) == HASH_KEY_IS_STRING) {
533 const char *class_name, *prop_name;
534
535 zend_unmangle_property_name(key, key_len-1, &class_name, &prop_name);
536 php_wddx_serialize_var(packet, *ent, prop_name, strlen(prop_name)+1 TSRMLS_CC);
537 } else {
538 key_len = slprintf(tmp_buf, sizeof(tmp_buf), "%ld", idx);
539 php_wddx_serialize_var(packet, *ent, tmp_buf, key_len TSRMLS_CC);
540 }
541 }
542 php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
543 }
544
545 zval_dtor(fname);
546 FREE_ZVAL(fname);
547
548 if (retval) {
549 zval_ptr_dtor(&retval);
550 }
551 }
552
553
554
555
556 static void php_wddx_serialize_array(wddx_packet *packet, zval *arr)
557 {
558 zval **ent;
559 char *key;
560 uint key_len;
561 int is_struct = 0, ent_type;
562 ulong idx;
563 HashTable *target_hash;
564 char tmp_buf[WDDX_BUF_LEN];
565 ulong ind = 0;
566 int type;
567 TSRMLS_FETCH();
568
569 target_hash = HASH_OF(arr);
570
571 for (zend_hash_internal_pointer_reset(target_hash);
572 zend_hash_get_current_data(target_hash, (void**)&ent) == SUCCESS;
573 zend_hash_move_forward(target_hash)) {
574
575 type = zend_hash_get_current_key(target_hash, &key, &idx, 0);
576
577 if (type == HASH_KEY_IS_STRING) {
578 is_struct = 1;
579 break;
580 }
581
582 if (idx != ind) {
583 is_struct = 1;
584 break;
585 }
586
587 ind++;
588 }
589
590 if (is_struct) {
591 php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
592 } else {
593 snprintf(tmp_buf, sizeof(tmp_buf), WDDX_ARRAY_S, zend_hash_num_elements(target_hash));
594 php_wddx_add_chunk(packet, tmp_buf);
595 }
596
597 for (zend_hash_internal_pointer_reset(target_hash);
598 zend_hash_get_current_data(target_hash, (void**)&ent) == SUCCESS;
599 zend_hash_move_forward(target_hash)) {
600 if (*ent == arr) {
601 continue;
602 }
603
604 if (is_struct) {
605 ent_type = zend_hash_get_current_key_ex(target_hash, &key, &key_len, &idx, 0, NULL);
606
607 if (ent_type == HASH_KEY_IS_STRING) {
608 php_wddx_serialize_var(packet, *ent, key, key_len TSRMLS_CC);
609 } else {
610 key_len = slprintf(tmp_buf, sizeof(tmp_buf), "%ld", idx);
611 php_wddx_serialize_var(packet, *ent, tmp_buf, key_len TSRMLS_CC);
612 }
613 } else {
614 php_wddx_serialize_var(packet, *ent, NULL, 0 TSRMLS_CC);
615 }
616 }
617
618 if (is_struct) {
619 php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
620 } else {
621 php_wddx_add_chunk_static(packet, WDDX_ARRAY_E);
622 }
623 }
624
625
626
627
628 void php_wddx_serialize_var(wddx_packet *packet, zval *var, char *name, int name_len TSRMLS_DC)
629 {
630 HashTable *ht;
631
632 if (name) {
633 size_t name_esc_len;
634 char *tmp_buf, *name_esc;
635
636 name_esc = php_escape_html_entities(name, name_len, &name_esc_len, 0, ENT_QUOTES, NULL TSRMLS_CC);
637 tmp_buf = emalloc(name_esc_len + sizeof(WDDX_VAR_S));
638 snprintf(tmp_buf, name_esc_len + sizeof(WDDX_VAR_S), WDDX_VAR_S, name_esc);
639 php_wddx_add_chunk(packet, tmp_buf);
640 efree(tmp_buf);
641 str_efree(name_esc);
642 }
643
644 switch(Z_TYPE_P(var)) {
645 case IS_STRING:
646 php_wddx_serialize_string(packet, var TSRMLS_CC);
647 break;
648
649 case IS_LONG:
650 case IS_DOUBLE:
651 php_wddx_serialize_number(packet, var);
652 break;
653
654 case IS_BOOL:
655 php_wddx_serialize_boolean(packet, var);
656 break;
657
658 case IS_NULL:
659 php_wddx_serialize_unset(packet);
660 break;
661
662 case IS_ARRAY:
663 ht = Z_ARRVAL_P(var);
664 if (ht->nApplyCount > 1) {
665 php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "WDDX doesn't support circular references");
666 return;
667 }
668 ht->nApplyCount++;
669 php_wddx_serialize_array(packet, var);
670 ht->nApplyCount--;
671 break;
672
673 case IS_OBJECT:
674 ht = Z_OBJPROP_P(var);
675 if (ht->nApplyCount > 1) {
676 php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "WDDX doesn't support circular references");
677 return;
678 }
679 ht->nApplyCount++;
680 php_wddx_serialize_object(packet, var);
681 ht->nApplyCount--;
682 break;
683 }
684
685 if (name) {
686 php_wddx_add_chunk_static(packet, WDDX_VAR_E);
687 }
688 }
689
690
691
692
693 static void php_wddx_add_var(wddx_packet *packet, zval *name_var)
694 {
695 zval **val;
696 HashTable *target_hash;
697 TSRMLS_FETCH();
698
699 if (Z_TYPE_P(name_var) == IS_STRING) {
700 if (!EG(active_symbol_table)) {
701 zend_rebuild_symbol_table(TSRMLS_C);
702 }
703 if (zend_hash_find(EG(active_symbol_table), Z_STRVAL_P(name_var),
704 Z_STRLEN_P(name_var)+1, (void**)&val) != FAILURE) {
705 php_wddx_serialize_var(packet, *val, Z_STRVAL_P(name_var), Z_STRLEN_P(name_var) TSRMLS_CC);
706 }
707 } else if (Z_TYPE_P(name_var) == IS_ARRAY || Z_TYPE_P(name_var) == IS_OBJECT) {
708 int is_array = Z_TYPE_P(name_var) == IS_ARRAY;
709
710 target_hash = HASH_OF(name_var);
711
712 if (is_array && target_hash->nApplyCount > 1) {
713 php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");
714 return;
715 }
716
717 zend_hash_internal_pointer_reset(target_hash);
718
719 while(zend_hash_get_current_data(target_hash, (void**)&val) == SUCCESS) {
720 if (is_array) {
721 target_hash->nApplyCount++;
722 }
723
724 php_wddx_add_var(packet, *val);
725
726 if (is_array) {
727 target_hash->nApplyCount--;
728 }
729 zend_hash_move_forward(target_hash);
730 }
731 }
732 }
733
734
735
736
737 static void php_wddx_push_element(void *user_data, const XML_Char *name, const XML_Char **atts)
738 {
739 st_entry ent;
740 wddx_stack *stack = (wddx_stack *)user_data;
741
742 if (!strcmp(name, EL_PACKET)) {
743 int i;
744
745 if (atts) for (i=0; atts[i]; i++) {
746 if (!strcmp(atts[i], EL_VERSION)) {
747
748 }
749 }
750 } else if (!strcmp(name, EL_STRING)) {
751 ent.type = ST_STRING;
752 SET_STACK_VARNAME;
753
754 ALLOC_ZVAL(ent.data);
755 INIT_PZVAL(ent.data);
756 Z_TYPE_P(ent.data) = IS_STRING;
757 Z_STRVAL_P(ent.data) = STR_EMPTY_ALLOC();
758 Z_STRLEN_P(ent.data) = 0;
759 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
760 } else if (!strcmp(name, EL_BINARY)) {
761 ent.type = ST_BINARY;
762 SET_STACK_VARNAME;
763
764 ALLOC_ZVAL(ent.data);
765 INIT_PZVAL(ent.data);
766 Z_TYPE_P(ent.data) = IS_STRING;
767 Z_STRVAL_P(ent.data) = STR_EMPTY_ALLOC();
768 Z_STRLEN_P(ent.data) = 0;
769 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
770 } else if (!strcmp(name, EL_CHAR)) {
771 int i;
772
773 if (atts) for (i = 0; atts[i]; i++) {
774 if (!strcmp(atts[i], EL_CHAR_CODE) && atts[++i] && atts[i][0]) {
775 char tmp_buf[2];
776
777 snprintf(tmp_buf, sizeof(tmp_buf), "%c", (char)strtol(atts[i], NULL, 16));
778 php_wddx_process_data(user_data, tmp_buf, strlen(tmp_buf));
779 break;
780 }
781 }
782 } else if (!strcmp(name, EL_NUMBER)) {
783 ent.type = ST_NUMBER;
784 SET_STACK_VARNAME;
785
786 ALLOC_ZVAL(ent.data);
787 INIT_PZVAL(ent.data);
788 Z_TYPE_P(ent.data) = IS_LONG;
789 Z_LVAL_P(ent.data) = 0;
790 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
791 } else if (!strcmp(name, EL_BOOLEAN)) {
792 int i;
793
794 if (atts) for (i = 0; atts[i]; i++) {
795 if (!strcmp(atts[i], EL_VALUE) && atts[++i] && atts[i][0]) {
796 ent.type = ST_BOOLEAN;
797 SET_STACK_VARNAME;
798
799 ALLOC_ZVAL(ent.data);
800 INIT_PZVAL(ent.data);
801 Z_TYPE_P(ent.data) = IS_BOOL;
802 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
803 php_wddx_process_data(user_data, atts[i], strlen(atts[i]));
804 break;
805 }
806 }
807 } else if (!strcmp(name, EL_NULL)) {
808 ent.type = ST_NULL;
809 SET_STACK_VARNAME;
810
811 ALLOC_ZVAL(ent.data);
812 INIT_PZVAL(ent.data);
813 ZVAL_NULL(ent.data);
814
815 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
816 } else if (!strcmp(name, EL_ARRAY)) {
817 ent.type = ST_ARRAY;
818 SET_STACK_VARNAME;
819
820 ALLOC_ZVAL(ent.data);
821 array_init(ent.data);
822 INIT_PZVAL(ent.data);
823 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
824 } else if (!strcmp(name, EL_STRUCT)) {
825 ent.type = ST_STRUCT;
826 SET_STACK_VARNAME;
827
828 ALLOC_ZVAL(ent.data);
829 array_init(ent.data);
830 INIT_PZVAL(ent.data);
831 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
832 } else if (!strcmp(name, EL_VAR)) {
833 int i;
834
835 if (atts) for (i = 0; atts[i]; i++) {
836 if (!strcmp(atts[i], EL_NAME) && atts[++i] && atts[i][0]) {
837 stack->varname = estrdup(atts[i]);
838 break;
839 }
840 }
841 } else if (!strcmp(name, EL_RECORDSET)) {
842 int i;
843
844 ent.type = ST_RECORDSET;
845 SET_STACK_VARNAME;
846 MAKE_STD_ZVAL(ent.data);
847 array_init(ent.data);
848
849 if (atts) for (i = 0; atts[i]; i++) {
850 if (!strcmp(atts[i], "fieldNames") && atts[++i] && atts[i][0]) {
851 zval *tmp;
852 char *key;
853 char *p1, *p2, *endp;
854
855 endp = (char *)atts[i] + strlen(atts[i]);
856 p1 = (char *)atts[i];
857 while ((p2 = php_memnstr(p1, ",", sizeof(",")-1, endp)) != NULL) {
858 key = estrndup(p1, p2 - p1);
859 MAKE_STD_ZVAL(tmp);
860 array_init(tmp);
861 add_assoc_zval_ex(ent.data, key, p2 - p1 + 1, tmp);
862 p1 = p2 + sizeof(",")-1;
863 efree(key);
864 }
865
866 if (p1 <= endp) {
867 MAKE_STD_ZVAL(tmp);
868 array_init(tmp);
869 add_assoc_zval_ex(ent.data, p1, endp - p1 + 1, tmp);
870 }
871
872 break;
873 }
874 }
875
876 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
877 } else if (!strcmp(name, EL_FIELD)) {
878 int i;
879 st_entry ent;
880
881 ent.type = ST_FIELD;
882 ent.varname = NULL;
883 ent.data = NULL;
884
885 if (atts) for (i = 0; atts[i]; i++) {
886 if (!strcmp(atts[i], EL_NAME) && atts[++i] && atts[i][0]) {
887 st_entry *recordset;
888 zval **field;
889
890 if (wddx_stack_top(stack, (void**)&recordset) == SUCCESS &&
891 recordset->type == ST_RECORDSET &&
892 zend_hash_find(Z_ARRVAL_P(recordset->data), (char*)atts[i], strlen(atts[i])+1, (void**)&field) == SUCCESS) {
893 ent.data = *field;
894 }
895
896 break;
897 }
898 }
899
900 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
901 } else if (!strcmp(name, EL_DATETIME)) {
902 ent.type = ST_DATETIME;
903 SET_STACK_VARNAME;
904
905 ALLOC_ZVAL(ent.data);
906 INIT_PZVAL(ent.data);
907 Z_TYPE_P(ent.data) = IS_LONG;
908 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
909 }
910 }
911
912
913
914
915 static void php_wddx_pop_element(void *user_data, const XML_Char *name)
916 {
917 st_entry *ent1, *ent2;
918 wddx_stack *stack = (wddx_stack *)user_data;
919 HashTable *target_hash;
920 zend_class_entry **pce;
921 zval *obj;
922 zval *tmp;
923 TSRMLS_FETCH();
924
925
926 if (stack->top == 0) {
927 return;
928 }
929
930 if (!strcmp(name, EL_STRING) || !strcmp(name, EL_NUMBER) ||
931 !strcmp(name, EL_BOOLEAN) || !strcmp(name, EL_NULL) ||
932 !strcmp(name, EL_ARRAY) || !strcmp(name, EL_STRUCT) ||
933 !strcmp(name, EL_RECORDSET) || !strcmp(name, EL_BINARY) ||
934 !strcmp(name, EL_DATETIME)) {
935 wddx_stack_top(stack, (void**)&ent1);
936
937 if (!ent1->data) {
938 if (stack->top > 1) {
939 stack->top--;
940 } else {
941 stack->done = 1;
942 }
943 efree(ent1);
944 return;
945 }
946
947 if (!strcmp(name, EL_BINARY)) {
948 int new_len=0;
949 unsigned char *new_str;
950
951 new_str = php_base64_decode(Z_STRVAL_P(ent1->data), Z_STRLEN_P(ent1->data), &new_len);
952 STR_FREE(Z_STRVAL_P(ent1->data));
953 Z_STRVAL_P(ent1->data) = new_str;
954 Z_STRLEN_P(ent1->data) = new_len;
955 }
956
957
958 if (Z_TYPE_P(ent1->data) == IS_OBJECT) {
959 zval *fname, *retval = NULL;
960
961 MAKE_STD_ZVAL(fname);
962 ZVAL_STRING(fname, "__wakeup", 1);
963
964 call_user_function_ex(NULL, &ent1->data, fname, &retval, 0, 0, 0, NULL TSRMLS_CC);
965
966 zval_dtor(fname);
967 FREE_ZVAL(fname);
968 if (retval) {
969 zval_ptr_dtor(&retval);
970 }
971 }
972
973 if (stack->top > 1) {
974 stack->top--;
975 wddx_stack_top(stack, (void**)&ent2);
976
977
978 if (ent2->type == ST_FIELD && ent2->data == NULL) {
979 zval_ptr_dtor(&ent1->data);
980 efree(ent1);
981 return;
982 }
983
984 if (Z_TYPE_P(ent2->data) == IS_ARRAY || Z_TYPE_P(ent2->data) == IS_OBJECT) {
985 target_hash = HASH_OF(ent2->data);
986
987 if (ent1->varname) {
988 if (!strcmp(ent1->varname, PHP_CLASS_NAME_VAR) &&
989 Z_TYPE_P(ent1->data) == IS_STRING && Z_STRLEN_P(ent1->data) &&
990 ent2->type == ST_STRUCT && Z_TYPE_P(ent2->data) == IS_ARRAY) {
991 zend_bool incomplete_class = 0;
992
993 zend_str_tolower(Z_STRVAL_P(ent1->data), Z_STRLEN_P(ent1->data));
994 if (zend_hash_find(EG(class_table), Z_STRVAL_P(ent1->data),
995 Z_STRLEN_P(ent1->data)+1, (void **) &pce)==FAILURE) {
996 incomplete_class = 1;
997 pce = &PHP_IC_ENTRY;
998 }
999
1000
1001 MAKE_STD_ZVAL(obj);
1002 object_init_ex(obj, *pce);
1003
1004
1005 zend_hash_merge(Z_OBJPROP_P(obj),
1006 Z_ARRVAL_P(ent2->data),
1007 (void (*)(void *)) zval_add_ref,
1008 (void *) &tmp, sizeof(zval *), 0);
1009
1010 if (incomplete_class) {
1011 php_store_class_name(obj, Z_STRVAL_P(ent1->data), Z_STRLEN_P(ent1->data));
1012 }
1013
1014
1015 zval_ptr_dtor(&ent2->data);
1016
1017
1018 ent2->data = obj;
1019
1020
1021 zval_ptr_dtor(&ent1->data);
1022 } else if (Z_TYPE_P(ent2->data) == IS_OBJECT) {
1023 zend_class_entry *old_scope = EG(scope);
1024
1025 EG(scope) = Z_OBJCE_P(ent2->data);
1026 Z_DELREF_P(ent1->data);
1027 add_property_zval(ent2->data, ent1->varname, ent1->data);
1028 EG(scope) = old_scope;
1029 } else {
1030 zend_symtable_update(target_hash, ent1->varname, strlen(ent1->varname)+1, &ent1->data, sizeof(zval *), NULL);
1031 }
1032 efree(ent1->varname);
1033 } else {
1034 zend_hash_next_index_insert(target_hash, &ent1->data, sizeof(zval *), NULL);
1035 }
1036 }
1037 efree(ent1);
1038 } else {
1039 stack->done = 1;
1040 }
1041 } else if (!strcmp(name, EL_VAR) && stack->varname) {
1042 efree(stack->varname);
1043 stack->varname = NULL;
1044 } else if (!strcmp(name, EL_FIELD)) {
1045 st_entry *ent;
1046 wddx_stack_top(stack, (void **)&ent);
1047 efree(ent);
1048 stack->top--;
1049 }
1050 }
1051
1052
1053
1054
1055 static void php_wddx_process_data(void *user_data, const XML_Char *s, int len)
1056 {
1057 st_entry *ent;
1058 wddx_stack *stack = (wddx_stack *)user_data;
1059 TSRMLS_FETCH();
1060
1061 if (!wddx_stack_is_empty(stack) && !stack->done) {
1062 wddx_stack_top(stack, (void**)&ent);
1063 switch (ent->type) {
1064 case ST_STRING:
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);
1068 Z_STRLEN_P(ent->data) = len;
1069 } else {
1070 Z_STRVAL_P(ent->data) = erealloc(Z_STRVAL_P(ent->data), Z_STRLEN_P(ent->data) + len + 1);
1071 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';
1074 }
1075 break;
1076
1077 case ST_BINARY:
1078 if (Z_STRLEN_P(ent->data) == 0) {
1079 STR_FREE(Z_STRVAL_P(ent->data));
1080 Z_STRVAL_P(ent->data) = estrndup(s, len + 1);
1081 } else {
1082 Z_STRVAL_P(ent->data) = erealloc(Z_STRVAL_P(ent->data), Z_STRLEN_P(ent->data) + len + 1);
1083 memcpy(Z_STRVAL_P(ent->data) + Z_STRLEN_P(ent->data), s, len);
1084 }
1085 Z_STRLEN_P(ent->data) += len;
1086 Z_STRVAL_P(ent->data)[Z_STRLEN_P(ent->data)] = '\0';
1087 break;
1088
1089 case ST_NUMBER:
1090 Z_TYPE_P(ent->data) = IS_STRING;
1091 Z_STRLEN_P(ent->data) = len;
1092 Z_STRVAL_P(ent->data) = estrndup(s, len);
1093 convert_scalar_to_number(ent->data TSRMLS_CC);
1094 break;
1095
1096 case ST_BOOLEAN:
1097 if (!strcmp(s, "true")) {
1098 Z_LVAL_P(ent->data) = 1;
1099 } else if (!strcmp(s, "false")) {
1100 Z_LVAL_P(ent->data) = 0;
1101 } else {
1102 zval_ptr_dtor(&ent->data);
1103 if (ent->varname) {
1104 efree(ent->varname);
1105 }
1106 ent->data = NULL;
1107 }
1108 break;
1109
1110 case ST_DATETIME: {
1111 char *tmp;
1112
1113 tmp = emalloc(len + 1);
1114 memcpy(tmp, s, len);
1115 tmp[len] = '\0';
1116
1117 Z_LVAL_P(ent->data) = php_parse_date(tmp, NULL);
1118
1119 if (Z_LVAL_P(ent->data) == -1) {
1120 Z_TYPE_P(ent->data) = IS_STRING;
1121 Z_STRLEN_P(ent->data) = len;
1122 Z_STRVAL_P(ent->data) = estrndup(s, len);
1123 }
1124 efree(tmp);
1125 }
1126 break;
1127
1128 default:
1129 break;
1130 }
1131 }
1132 }
1133
1134
1135
1136
1137 int php_wddx_deserialize_ex(char *value, int vallen, zval *return_value)
1138 {
1139 wddx_stack stack;
1140 XML_Parser parser;
1141 st_entry *ent;
1142 int retval;
1143
1144 wddx_stack_init(&stack);
1145 parser = XML_ParserCreate("UTF-8");
1146
1147 XML_SetUserData(parser, &stack);
1148 XML_SetElementHandler(parser, php_wddx_push_element, php_wddx_pop_element);
1149 XML_SetCharacterDataHandler(parser, php_wddx_process_data);
1150
1151 XML_Parse(parser, value, vallen, 1);
1152
1153 XML_ParserFree(parser);
1154
1155 if (stack.top == 1) {
1156 wddx_stack_top(&stack, (void**)&ent);
1157 *return_value = *(ent->data);
1158 zval_copy_ctor(return_value);
1159 retval = SUCCESS;
1160 } else {
1161 retval = FAILURE;
1162 }
1163
1164 wddx_stack_destroy(&stack);
1165
1166 return retval;
1167 }
1168
1169
1170
1171
1172 PHP_FUNCTION(wddx_serialize_value)
1173 {
1174 zval *var;
1175 char *comment = NULL;
1176 int comment_len = 0;
1177 wddx_packet *packet;
1178
1179 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|s", &var, &comment, &comment_len) == FAILURE) {
1180 return;
1181 }
1182
1183 packet = php_wddx_constructor();
1184
1185 php_wddx_packet_start(packet, comment, comment_len);
1186 php_wddx_serialize_var(packet, var, NULL, 0 TSRMLS_CC);
1187 php_wddx_packet_end(packet);
1188
1189 ZVAL_STRINGL(return_value, packet->c, packet->len, 1);
1190 smart_str_free(packet);
1191 efree(packet);
1192 }
1193
1194
1195
1196
1197 PHP_FUNCTION(wddx_serialize_vars)
1198 {
1199 int num_args, i;
1200 wddx_packet *packet;
1201 zval ***args = NULL;
1202
1203 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &num_args) == FAILURE) {
1204 return;
1205 }
1206
1207 packet = php_wddx_constructor();
1208
1209 php_wddx_packet_start(packet, NULL, 0);
1210 php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
1211
1212 for (i=0; i<num_args; i++) {
1213 if (Z_TYPE_PP(args[i]) != IS_ARRAY && Z_TYPE_PP(args[i]) != IS_OBJECT) {
1214 convert_to_string_ex(args[i]);
1215 }
1216 php_wddx_add_var(packet, *args[i]);
1217 }
1218
1219 php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
1220 php_wddx_packet_end(packet);
1221
1222 efree(args);
1223
1224 ZVAL_STRINGL(return_value, packet->c, packet->len, 1);
1225 smart_str_free(packet);
1226 efree(packet);
1227 }
1228
1229
1230
1231
1232 wddx_packet *php_wddx_constructor(void)
1233 {
1234 smart_str *packet;
1235
1236 packet = (smart_str *)emalloc(sizeof(smart_str));
1237 packet->c = NULL;
1238
1239 return packet;
1240 }
1241
1242
1243
1244
1245 void php_wddx_destructor(wddx_packet *packet)
1246 {
1247 smart_str_free(packet);
1248 efree(packet);
1249 }
1250
1251
1252
1253
1254 PHP_FUNCTION(wddx_packet_start)
1255 {
1256 char *comment = NULL;
1257 int comment_len = 0;
1258 wddx_packet *packet;
1259
1260 comment = NULL;
1261
1262 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &comment, &comment_len) == FAILURE) {
1263 return;
1264 }
1265
1266 packet = php_wddx_constructor();
1267
1268 php_wddx_packet_start(packet, comment, comment_len);
1269 php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
1270
1271 ZEND_REGISTER_RESOURCE(return_value, packet, le_wddx);
1272 }
1273
1274
1275
1276
1277 PHP_FUNCTION(wddx_packet_end)
1278 {
1279 zval *packet_id;
1280 wddx_packet *packet = NULL;
1281
1282 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &packet_id) == FAILURE) {
1283 return;
1284 }
1285
1286 ZEND_FETCH_RESOURCE(packet, wddx_packet *, &packet_id, -1, "WDDX packet ID", le_wddx);
1287
1288 php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
1289
1290 php_wddx_packet_end(packet);
1291
1292 ZVAL_STRINGL(return_value, packet->c, packet->len, 1);
1293
1294 zend_list_delete(Z_LVAL_P(packet_id));
1295 }
1296
1297
1298
1299
1300 PHP_FUNCTION(wddx_add_vars)
1301 {
1302 int num_args, i;
1303 zval ***args = NULL;
1304 zval *packet_id;
1305 wddx_packet *packet = NULL;
1306
1307 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r+", &packet_id, &args, &num_args) == FAILURE) {
1308 return;
1309 }
1310
1311 if (!ZEND_FETCH_RESOURCE_NO_RETURN(packet, wddx_packet *, &packet_id, -1, "WDDX packet ID", le_wddx)) {
1312 efree(args);
1313 RETURN_FALSE;
1314 }
1315
1316 if (!packet) {
1317 efree(args);
1318 RETURN_FALSE;
1319 }
1320
1321 for (i=0; i<num_args; i++) {
1322 if (Z_TYPE_PP(args[i]) != IS_ARRAY && Z_TYPE_PP(args[i]) != IS_OBJECT) {
1323 convert_to_string_ex(args[i]);
1324 }
1325 php_wddx_add_var(packet, (*args[i]));
1326 }
1327
1328 efree(args);
1329 RETURN_TRUE;
1330 }
1331
1332
1333
1334
1335 PHP_FUNCTION(wddx_deserialize)
1336 {
1337 zval *packet;
1338 char *payload;
1339 int payload_len;
1340 php_stream *stream = NULL;
1341
1342 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &packet) == FAILURE) {
1343 return;
1344 }
1345
1346 if (Z_TYPE_P(packet) == IS_STRING) {
1347 payload = Z_STRVAL_P(packet);
1348 payload_len = Z_STRLEN_P(packet);
1349 } else if (Z_TYPE_P(packet) == IS_RESOURCE) {
1350 php_stream_from_zval(stream, &packet);
1351 if (stream) {
1352 payload_len = php_stream_copy_to_mem(stream, &payload, PHP_STREAM_COPY_ALL, 0);
1353 }
1354 } else {
1355 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expecting parameter 1 to be a string or a stream");
1356 return;
1357 }
1358
1359 if (payload_len == 0) {
1360 return;
1361 }
1362
1363 php_wddx_deserialize_ex(payload, payload_len, return_value);
1364
1365 if (stream) {
1366 pefree(payload, 0);
1367 }
1368 }
1369
1370
1371 #endif
1372
1373
1374
1375
1376
1377
1378
1379
1380