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 "zend_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(Z_STRVAL_P(a), Z_STRLEN_P(a), (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 PHP_WDDX_VERSION,
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 zval_ptr_dtor(&((st_entry *)stack->elements[i])->data);
234 if (((st_entry *)stack->elements[i])->varname) {
235 efree(((st_entry *)stack->elements[i])->varname);
236 }
237 efree(stack->elements[i]);
238 }
239 efree(stack->elements);
240 }
241 return SUCCESS;
242 }
243
244
245
246
247 static void release_wddx_packet_rsrc(zend_resource *rsrc)
248 {
249 smart_str *str = (smart_str *)rsrc->ptr;
250 smart_str_free(str);
251 efree(str);
252 }
253
254
255 #include "ext/session/php_session.h"
256
257 #if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
258
259
260 PS_SERIALIZER_ENCODE_FUNC(wddx)
261 {
262 wddx_packet *packet;
263 zend_string *str;
264 PS_ENCODE_VARS;
265
266 packet = php_wddx_constructor();
267
268 php_wddx_packet_start(packet, NULL, 0);
269 php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
270
271 PS_ENCODE_LOOP(
272 php_wddx_serialize_var(packet, struc, key);
273 );
274
275 php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
276 php_wddx_packet_end(packet);
277 smart_str_0(packet);
278 str = zend_string_copy(packet->s);
279 php_wddx_destructor(packet);
280
281 return str;
282 }
283
284
285
286
287 PS_SERIALIZER_DECODE_FUNC(wddx)
288 {
289 zval retval;
290 zval *ent;
291 zend_string *key;
292 zend_ulong idx;
293 int ret;
294
295 if (vallen == 0) {
296 return SUCCESS;
297 }
298
299 ZVAL_UNDEF(&retval);
300 if ((ret = php_wddx_deserialize_ex(val, vallen, &retval)) == SUCCESS) {
301 if (Z_TYPE(retval) != IS_ARRAY) {
302 zval_dtor(&retval);
303 return FAILURE;
304 }
305 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL(retval), idx, key, ent) {
306 if (key == NULL) {
307 key = zend_long_to_str(idx);
308 } else {
309 zend_string_addref(key);
310 }
311 if (php_set_session_var(key, ent, NULL)) {
312 if (Z_REFCOUNTED_P(ent)) Z_ADDREF_P(ent);
313 }
314 PS_ADD_VAR(key);
315 zend_string_release(key);
316 } ZEND_HASH_FOREACH_END();
317 }
318
319 zval_ptr_dtor(&retval);
320
321 return ret;
322 }
323
324 #endif
325
326
327
328 PHP_MINIT_FUNCTION(wddx)
329 {
330 le_wddx = zend_register_list_destructors_ex(release_wddx_packet_rsrc, NULL, "wddx", module_number);
331
332 #if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
333 php_session_register_serializer("wddx",
334 PS_SERIALIZER_ENCODE_NAME(wddx),
335 PS_SERIALIZER_DECODE_NAME(wddx));
336 #endif
337
338 return SUCCESS;
339 }
340
341
342
343
344 PHP_MINFO_FUNCTION(wddx)
345 {
346 php_info_print_table_start();
347 #if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
348 php_info_print_table_header(2, "WDDX Support", "enabled" );
349 php_info_print_table_row(2, "WDDX Session Serializer", "enabled" );
350 #else
351 php_info_print_table_row(2, "WDDX Support", "enabled" );
352 #endif
353 php_info_print_table_end();
354 }
355
356
357
358
359 void php_wddx_packet_start(wddx_packet *packet, char *comment, size_t comment_len)
360 {
361 php_wddx_add_chunk_static(packet, WDDX_PACKET_S);
362 if (comment) {
363 php_wddx_add_chunk_static(packet, WDDX_HEADER_S);
364 php_wddx_add_chunk_static(packet, WDDX_COMMENT_S);
365 php_wddx_add_chunk_ex(packet, comment, comment_len);
366 php_wddx_add_chunk_static(packet, WDDX_COMMENT_E);
367 php_wddx_add_chunk_static(packet, WDDX_HEADER_E);
368 } else {
369 php_wddx_add_chunk_static(packet, WDDX_HEADER);
370 }
371 php_wddx_add_chunk_static(packet, WDDX_DATA_S);
372 }
373
374
375
376
377 void php_wddx_packet_end(wddx_packet *packet)
378 {
379 php_wddx_add_chunk_static(packet, WDDX_DATA_E);
380 php_wddx_add_chunk_static(packet, WDDX_PACKET_E);
381 }
382
383
384 #define FLUSH_BUF() \
385 if (l > 0) { \
386 php_wddx_add_chunk_ex(packet, buf, l); \
387 l = 0; \
388 }
389
390
391
392 static void php_wddx_serialize_string(wddx_packet *packet, zval *var)
393 {
394 php_wddx_add_chunk_static(packet, WDDX_STRING_S);
395
396 if (Z_STRLEN_P(var) > 0) {
397 zend_string *buf = php_escape_html_entities(
398 (unsigned char *) Z_STRVAL_P(var), Z_STRLEN_P(var), 0, ENT_QUOTES, NULL);
399
400 php_wddx_add_chunk_ex(packet, ZSTR_VAL(buf), ZSTR_LEN(buf));
401
402 zend_string_release(buf);
403 }
404 php_wddx_add_chunk_static(packet, WDDX_STRING_E);
405 }
406
407
408
409
410 static void php_wddx_serialize_number(wddx_packet *packet, zval *var)
411 {
412 char tmp_buf[WDDX_BUF_LEN];
413 zend_string *str = zval_get_string(var);
414 snprintf(tmp_buf, sizeof(tmp_buf), WDDX_NUMBER, ZSTR_VAL(str));
415 zend_string_release(str);
416
417 php_wddx_add_chunk(packet, tmp_buf);
418 }
419
420
421
422
423 static void php_wddx_serialize_boolean(wddx_packet *packet, zval *var)
424 {
425 php_wddx_add_chunk(packet, Z_TYPE_P(var) == IS_TRUE ? WDDX_BOOLEAN_TRUE : WDDX_BOOLEAN_FALSE);
426 }
427
428
429
430
431 static void php_wddx_serialize_unset(wddx_packet *packet)
432 {
433 php_wddx_add_chunk_static(packet, WDDX_NULL);
434 }
435
436
437
438
439 static void php_wddx_serialize_object(wddx_packet *packet, zval *obj)
440 {
441
442 zval *ent, fname, *varname;
443 zval retval;
444 zend_string *key;
445 zend_ulong idx;
446 char tmp_buf[WDDX_BUF_LEN];
447 HashTable *objhash, *sleephash;
448
449 ZVAL_STRING(&fname, "__sleep");
450
451
452
453
454 if (call_user_function_ex(CG(function_table), obj, &fname, &retval, 0, 0, 1, NULL) == SUCCESS) {
455 if (!Z_ISUNDEF(retval) && (sleephash = HASH_OF(&retval))) {
456 PHP_CLASS_ATTRIBUTES;
457
458 PHP_SET_CLASS_ATTRIBUTES(obj);
459
460 php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
461 snprintf(tmp_buf, WDDX_BUF_LEN, WDDX_VAR_S, PHP_CLASS_NAME_VAR);
462 php_wddx_add_chunk(packet, tmp_buf);
463 php_wddx_add_chunk_static(packet, WDDX_STRING_S);
464 php_wddx_add_chunk_ex(packet, ZSTR_VAL(class_name), ZSTR_LEN(class_name));
465 php_wddx_add_chunk_static(packet, WDDX_STRING_E);
466 php_wddx_add_chunk_static(packet, WDDX_VAR_E);
467
468 PHP_CLEANUP_CLASS_ATTRIBUTES();
469
470 objhash = Z_OBJPROP_P(obj);
471
472 ZEND_HASH_FOREACH_VAL(sleephash, varname) {
473 if (Z_TYPE_P(varname) != IS_STRING) {
474 php_error_docref(NULL, E_NOTICE, "__sleep should return an array only containing the names of instance-variables to serialize.");
475 continue;
476 }
477
478 if ((ent = zend_hash_find(objhash, Z_STR_P(varname))) != NULL) {
479 php_wddx_serialize_var(packet, ent, Z_STR_P(varname));
480 }
481 } ZEND_HASH_FOREACH_END();
482
483 php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
484 }
485 } else {
486 PHP_CLASS_ATTRIBUTES;
487
488 PHP_SET_CLASS_ATTRIBUTES(obj);
489
490 php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
491 snprintf(tmp_buf, WDDX_BUF_LEN, WDDX_VAR_S, PHP_CLASS_NAME_VAR);
492 php_wddx_add_chunk(packet, tmp_buf);
493 php_wddx_add_chunk_static(packet, WDDX_STRING_S);
494 php_wddx_add_chunk_ex(packet, ZSTR_VAL(class_name), ZSTR_LEN(class_name));
495 php_wddx_add_chunk_static(packet, WDDX_STRING_E);
496 php_wddx_add_chunk_static(packet, WDDX_VAR_E);
497
498 PHP_CLEANUP_CLASS_ATTRIBUTES();
499
500 objhash = Z_OBJPROP_P(obj);
501 ZEND_HASH_FOREACH_KEY_VAL(objhash, idx, key, ent) {
502 if (ent == obj) {
503 continue;
504 }
505 if (key) {
506 const char *class_name, *prop_name;
507 size_t prop_name_len;
508 zend_string *tmp;
509
510 zend_unmangle_property_name_ex(key, &class_name, &prop_name, &prop_name_len);
511 tmp = zend_string_init(prop_name, prop_name_len, 0);
512 php_wddx_serialize_var(packet, ent, tmp);
513 zend_string_release(tmp);
514 } else {
515 key = zend_long_to_str(idx);
516 php_wddx_serialize_var(packet, ent, key);
517 zend_string_release(key);
518 }
519 } ZEND_HASH_FOREACH_END();
520 php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
521 }
522
523 zval_ptr_dtor(&fname);
524 zval_ptr_dtor(&retval);
525 }
526
527
528
529
530 static void php_wddx_serialize_array(wddx_packet *packet, zval *arr)
531 {
532 zval *ent;
533 zend_string *key;
534 int is_struct = 0;
535 zend_ulong idx;
536 HashTable *target_hash;
537 char tmp_buf[WDDX_BUF_LEN];
538 zend_ulong ind = 0;
539
540 target_hash = Z_ARRVAL_P(arr);
541 ZEND_HASH_FOREACH_KEY(target_hash, idx, key) {
542 if (key) {
543 is_struct = 1;
544 break;
545 }
546
547 if (idx != ind) {
548 is_struct = 1;
549 break;
550 }
551 ind++;
552 } ZEND_HASH_FOREACH_END();
553
554 if (is_struct) {
555 php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
556 } else {
557 snprintf(tmp_buf, sizeof(tmp_buf), WDDX_ARRAY_S, zend_hash_num_elements(target_hash));
558 php_wddx_add_chunk(packet, tmp_buf);
559 }
560
561 ZEND_HASH_FOREACH_KEY_VAL(target_hash, idx, key, ent) {
562 if (ent == arr) {
563 continue;
564 }
565
566 if (is_struct) {
567 if (key) {
568 php_wddx_serialize_var(packet, ent, key);
569 } else {
570 key = zend_long_to_str(idx);
571 php_wddx_serialize_var(packet, ent, key);
572 zend_string_release(key);
573 }
574 } else {
575 php_wddx_serialize_var(packet, ent, NULL);
576 }
577 } ZEND_HASH_FOREACH_END();
578
579 if (is_struct) {
580 php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
581 } else {
582 php_wddx_add_chunk_static(packet, WDDX_ARRAY_E);
583 }
584 }
585
586
587
588
589 void php_wddx_serialize_var(wddx_packet *packet, zval *var, zend_string *name)
590 {
591 HashTable *ht;
592
593 if (name) {
594 char *tmp_buf;
595 zend_string *name_esc = php_escape_html_entities((unsigned char *) ZSTR_VAL(name), ZSTR_LEN(name), 0, ENT_QUOTES, NULL);
596 tmp_buf = emalloc(ZSTR_LEN(name_esc) + sizeof(WDDX_VAR_S));
597 snprintf(tmp_buf, ZSTR_LEN(name_esc) + sizeof(WDDX_VAR_S), WDDX_VAR_S, ZSTR_VAL(name_esc));
598 php_wddx_add_chunk(packet, tmp_buf);
599 efree(tmp_buf);
600 zend_string_release(name_esc);
601 }
602
603 if (Z_TYPE_P(var) == IS_INDIRECT) {
604 var = Z_INDIRECT_P(var);
605 }
606 ZVAL_DEREF(var);
607 switch (Z_TYPE_P(var)) {
608 case IS_STRING:
609 php_wddx_serialize_string(packet, var);
610 break;
611
612 case IS_LONG:
613 case IS_DOUBLE:
614 php_wddx_serialize_number(packet, var);
615 break;
616
617 case IS_TRUE:
618 case IS_FALSE:
619 php_wddx_serialize_boolean(packet, var);
620 break;
621
622 case IS_NULL:
623 php_wddx_serialize_unset(packet);
624 break;
625
626 case IS_ARRAY:
627 ht = Z_ARRVAL_P(var);
628 if (ht->u.v.nApplyCount > 1) {
629 php_error_docref(NULL, E_RECOVERABLE_ERROR, "WDDX doesn't support circular references");
630 return;
631 }
632 if (ZEND_HASH_APPLY_PROTECTION(ht)) {
633 ht->u.v.nApplyCount++;
634 }
635 php_wddx_serialize_array(packet, var);
636 if (ZEND_HASH_APPLY_PROTECTION(ht)) {
637 ht->u.v.nApplyCount--;
638 }
639 break;
640
641 case IS_OBJECT:
642 ht = Z_OBJPROP_P(var);
643 if (ht->u.v.nApplyCount > 1) {
644 php_error_docref(NULL, E_RECOVERABLE_ERROR, "WDDX doesn't support circular references");
645 return;
646 }
647 ht->u.v.nApplyCount++;
648 php_wddx_serialize_object(packet, var);
649 ht->u.v.nApplyCount--;
650 break;
651 }
652
653 if (name) {
654 php_wddx_add_chunk_static(packet, WDDX_VAR_E);
655 }
656 }
657
658
659
660
661 static void php_wddx_add_var(wddx_packet *packet, zval *name_var)
662 {
663 zval *val;
664 HashTable *target_hash;
665
666 if (Z_TYPE_P(name_var) == IS_STRING) {
667 zend_array *symbol_table = zend_rebuild_symbol_table();
668 if ((val = zend_hash_find(symbol_table, Z_STR_P(name_var))) != NULL) {
669 if (Z_TYPE_P(val) == IS_INDIRECT) {
670 val = Z_INDIRECT_P(val);
671 }
672 php_wddx_serialize_var(packet, val, Z_STR_P(name_var));
673 }
674 } else if (Z_TYPE_P(name_var) == IS_ARRAY || Z_TYPE_P(name_var) == IS_OBJECT) {
675 int is_array = Z_TYPE_P(name_var) == IS_ARRAY;
676
677 target_hash = HASH_OF(name_var);
678
679 if (is_array && target_hash->u.v.nApplyCount > 1) {
680 php_error_docref(NULL, E_WARNING, "recursion detected");
681 return;
682 }
683
684 if (Z_IMMUTABLE_P(name_var)) {
685 ZEND_HASH_FOREACH_VAL(target_hash, val) {
686 php_wddx_add_var(packet, val);
687 } ZEND_HASH_FOREACH_END();
688 } else {
689 ZEND_HASH_FOREACH_VAL(target_hash, val) {
690 if (is_array) {
691 target_hash->u.v.nApplyCount++;
692 }
693
694 ZVAL_DEREF(val);
695 php_wddx_add_var(packet, val);
696
697 if (is_array) {
698 target_hash->u.v.nApplyCount--;
699 }
700 } ZEND_HASH_FOREACH_END();
701 }
702 }
703 }
704
705
706
707
708 static void php_wddx_push_element(void *user_data, const XML_Char *name, const XML_Char **atts)
709 {
710 st_entry ent;
711 wddx_stack *stack = (wddx_stack *)user_data;
712 if (!strcmp((char *)name, EL_PACKET)) {
713 int i;
714
715 if (atts) for (i=0; atts[i]; i++) {
716 if (!strcmp((char *)atts[i], EL_VERSION)) {
717
718 }
719 }
720 } else if (!strcmp((char *)name, EL_STRING)) {
721 ent.type = ST_STRING;
722 SET_STACK_VARNAME;
723
724 ZVAL_STR(&ent.data, ZSTR_EMPTY_ALLOC());
725 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
726 } else if (!strcmp((char *)name, EL_BINARY)) {
727 ent.type = ST_BINARY;
728 SET_STACK_VARNAME;
729
730 ZVAL_STR(&ent.data, ZSTR_EMPTY_ALLOC());
731 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
732 } else if (!strcmp((char *)name, EL_CHAR)) {
733 int i;
734
735 if (atts) for (i = 0; atts[i]; i++) {
736 if (!strcmp((char *)atts[i], EL_CHAR_CODE) && atts[++i] && atts[i][0]) {
737 char tmp_buf[2];
738
739 snprintf(tmp_buf, sizeof(tmp_buf), "%c", (char)strtol((char *)atts[i], NULL, 16));
740 php_wddx_process_data(user_data, (XML_Char *) tmp_buf, strlen(tmp_buf));
741 break;
742 }
743 }
744 } else if (!strcmp((char *)name, EL_NUMBER)) {
745 ent.type = ST_NUMBER;
746 SET_STACK_VARNAME;
747
748 ZVAL_LONG(&ent.data, 0);
749 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
750 } else if (!strcmp((char *)name, EL_BOOLEAN)) {
751 int i;
752
753 if (atts) for (i = 0; atts[i]; i++) {
754 if (!strcmp((char *)atts[i], EL_VALUE) && atts[++i] && atts[i][0]) {
755 ent.type = ST_BOOLEAN;
756 SET_STACK_VARNAME;
757
758 ZVAL_TRUE(&ent.data);
759 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
760 php_wddx_process_data(user_data, atts[i], strlen((char *)atts[i]));
761 break;
762 }
763 }
764 } else if (!strcmp((char *)name, EL_NULL)) {
765 ent.type = ST_NULL;
766 SET_STACK_VARNAME;
767
768 ZVAL_NULL(&ent.data);
769
770 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
771 } else if (!strcmp((char *)name, EL_ARRAY)) {
772 ent.type = ST_ARRAY;
773 SET_STACK_VARNAME;
774
775 array_init(&ent.data);
776 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
777 } else if (!strcmp((char *)name, EL_STRUCT)) {
778 ent.type = ST_STRUCT;
779 SET_STACK_VARNAME;
780 array_init(&ent.data);
781 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
782 } else if (!strcmp((char *)name, EL_VAR)) {
783 int i;
784
785 if (atts) for (i = 0; atts[i]; i++) {
786 if (!strcmp((char *)atts[i], EL_NAME) && atts[++i] && atts[i][0]) {
787 stack->varname = estrdup((char *)atts[i]);
788 break;
789 }
790 }
791 } else if (!strcmp((char *)name, EL_RECORDSET)) {
792 int i;
793
794 ent.type = ST_RECORDSET;
795 SET_STACK_VARNAME;
796 array_init(&ent.data);
797
798 if (atts) for (i = 0; atts[i]; i++) {
799 if (!strcmp((char *)atts[i], "fieldNames") && atts[++i] && atts[i][0]) {
800 zval tmp;
801 char *key;
802 const char *p1, *p2, *endp;
803
804 endp = (char *)atts[i] + strlen((char *)atts[i]);
805 p1 = (char *)atts[i];
806 while ((p2 = php_memnstr(p1, ",", sizeof(",")-1, endp)) != NULL) {
807 key = estrndup(p1, p2 - p1);
808 array_init(&tmp);
809 add_assoc_zval_ex(&ent.data, key, p2 - p1, &tmp);
810 p1 = p2 + sizeof(",")-1;
811 efree(key);
812 }
813
814 if (p1 <= endp) {
815 array_init(&tmp);
816 add_assoc_zval_ex(&ent.data, p1, endp - p1, &tmp);
817 }
818
819 break;
820 }
821 }
822
823 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
824 } else if (!strcmp((char *)name, EL_FIELD)) {
825 int i;
826 st_entry ent;
827
828 ent.type = ST_FIELD;
829 ent.varname = NULL;
830 ZVAL_UNDEF(&ent.data);
831
832 if (atts) for (i = 0; atts[i]; i++) {
833 if (!strcmp((char *)atts[i], EL_NAME) && atts[++i] && atts[i][0]) {
834 st_entry *recordset;
835 zval *field;
836
837 if (wddx_stack_top(stack, (void**)&recordset) == SUCCESS &&
838 recordset->type == ST_RECORDSET &&
839 (field = zend_hash_str_find(Z_ARRVAL(recordset->data), (char*)atts[i], strlen((char *)atts[i]))) != NULL) {
840 ZVAL_COPY_VALUE(&ent.data, field);
841 }
842
843 break;
844 }
845 }
846
847 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
848 } else if (!strcmp((char *)name, EL_DATETIME)) {
849 ent.type = ST_DATETIME;
850 SET_STACK_VARNAME;
851
852 ZVAL_LONG(&ent.data, 0);
853 wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
854 }
855 }
856
857
858
859
860 static void php_wddx_pop_element(void *user_data, const XML_Char *name)
861 {
862 st_entry *ent1, *ent2;
863 wddx_stack *stack = (wddx_stack *)user_data;
864 HashTable *target_hash;
865 zend_class_entry *pce;
866 zval obj;
867
868
869 if (stack->top == 0) {
870 return;
871 }
872
873 if (!strcmp((char *)name, EL_STRING) || !strcmp((char *)name, EL_NUMBER) ||
874 !strcmp((char *)name, EL_BOOLEAN) || !strcmp((char *)name, EL_NULL) ||
875 !strcmp((char *)name, EL_ARRAY) || !strcmp((char *)name, EL_STRUCT) ||
876 !strcmp((char *)name, EL_RECORDSET) || !strcmp((char *)name, EL_BINARY) ||
877 !strcmp((char *)name, EL_DATETIME)) {
878 wddx_stack_top(stack, (void**)&ent1);
879
880 if (Z_TYPE(ent1->data) == IS_UNDEF) {
881 if (stack->top > 1) {
882 stack->top--;
883 } else {
884 stack->done = 1;
885 }
886 efree(ent1);
887 return;
888 }
889
890 if (!strcmp((char *)name, EL_BINARY)) {
891 zend_string *new_str = php_base64_decode(
892 (unsigned char *)Z_STRVAL(ent1->data), Z_STRLEN(ent1->data));
893 zval_ptr_dtor(&ent1->data);
894 ZVAL_STR(&ent1->data, new_str);
895 }
896
897
898 if (Z_TYPE(ent1->data) == IS_OBJECT) {
899 zval fname, retval;
900
901 ZVAL_STRING(&fname, "__wakeup");
902
903 call_user_function_ex(NULL, &ent1->data, &fname, &retval, 0, 0, 0, NULL);
904
905 zval_ptr_dtor(&fname);
906 zval_ptr_dtor(&retval);
907 }
908
909 if (stack->top > 1) {
910 stack->top--;
911 wddx_stack_top(stack, (void**)&ent2);
912
913
914 if (ent2->type == ST_FIELD && Z_ISUNDEF(ent2->data)) {
915 zval_ptr_dtor(&ent1->data);
916 efree(ent1);
917 return;
918 }
919
920 if (Z_TYPE(ent2->data) == IS_ARRAY || Z_TYPE(ent2->data) == IS_OBJECT) {
921 target_hash = HASH_OF(&ent2->data);
922
923 if (ent1->varname) {
924 if (!strcmp(ent1->varname, PHP_CLASS_NAME_VAR) &&
925 Z_TYPE(ent1->data) == IS_STRING && Z_STRLEN(ent1->data) &&
926 ent2->type == ST_STRUCT && Z_TYPE(ent2->data) == IS_ARRAY) {
927 zend_bool incomplete_class = 0;
928
929 zend_str_tolower(Z_STRVAL(ent1->data), Z_STRLEN(ent1->data));
930 zend_string_forget_hash_val(Z_STR(ent1->data));
931 if ((pce = zend_hash_find_ptr(EG(class_table), Z_STR(ent1->data))) == NULL) {
932 incomplete_class = 1;
933 pce = PHP_IC_ENTRY;
934 }
935
936
937 object_init_ex(&obj, pce);
938
939
940 zend_hash_merge(Z_OBJPROP(obj),
941 Z_ARRVAL(ent2->data),
942 zval_add_ref, 0);
943
944 if (incomplete_class) {
945 php_store_class_name(&obj, Z_STRVAL(ent1->data), Z_STRLEN(ent1->data));
946 }
947
948
949 zval_ptr_dtor(&ent2->data);
950
951
952 ZVAL_COPY_VALUE(&ent2->data, &obj);
953
954
955 zval_ptr_dtor(&ent1->data);
956 } else if (Z_TYPE(ent2->data) == IS_OBJECT) {
957 zend_class_entry *old_scope = EG(scope);
958
959 EG(scope) = Z_OBJCE(ent2->data);
960 add_property_zval(&ent2->data, ent1->varname, &ent1->data);
961 if Z_REFCOUNTED(ent1->data) Z_DELREF(ent1->data);
962 EG(scope) = old_scope;
963 } else {
964 zend_symtable_str_update(target_hash, ent1->varname, strlen(ent1->varname), &ent1->data);
965 }
966 efree(ent1->varname);
967 } else {
968 zend_hash_next_index_insert(target_hash, &ent1->data);
969 }
970 }
971 efree(ent1);
972 } else {
973 stack->done = 1;
974 }
975 } else if (!strcmp((char *)name, EL_VAR) && stack->varname) {
976 efree(stack->varname);
977 stack->varname = NULL;
978 } else if (!strcmp((char *)name, EL_FIELD)) {
979 st_entry *ent;
980 wddx_stack_top(stack, (void **)&ent);
981 efree(ent);
982 stack->top--;
983 }
984 }
985
986
987
988
989 static void php_wddx_process_data(void *user_data, const XML_Char *s, int len)
990 {
991 st_entry *ent;
992 wddx_stack *stack = (wddx_stack *)user_data;
993
994 if (!wddx_stack_is_empty(stack) && !stack->done) {
995 wddx_stack_top(stack, (void**)&ent);
996 switch (ent->type) {
997 case ST_BINARY:
998 case ST_STRING:
999 if (Z_STRLEN(ent->data) == 0) {
1000 zval_ptr_dtor(&ent->data);
1001 ZVAL_STRINGL(&ent->data, (char *)s, len);
1002 } else {
1003 Z_STR(ent->data) = zend_string_extend(Z_STR(ent->data), Z_STRLEN(ent->data) + len, 0);
1004 memcpy(Z_STRVAL(ent->data) + Z_STRLEN(ent->data) - len, (char *)s, len);
1005 Z_STRVAL(ent->data)[Z_STRLEN(ent->data)] = '\0';
1006 }
1007 break;
1008 case ST_NUMBER:
1009 ZVAL_STRINGL(&ent->data, (char *)s, len);
1010 convert_scalar_to_number(&ent->data);
1011 break;
1012
1013 case ST_BOOLEAN:
1014 if (!strcmp((char *)s, "true")) {
1015 Z_LVAL(ent->data) = 1;
1016 } else if (!strcmp((char *)s, "false")) {
1017 Z_LVAL(ent->data) = 0;
1018 } else {
1019 zval_ptr_dtor(&ent->data);
1020 if (ent->varname) {
1021 efree(ent->varname);
1022 }
1023 ZVAL_UNDEF(&ent->data);
1024 }
1025 break;
1026
1027 case ST_DATETIME: {
1028 char *tmp;
1029
1030 tmp = emalloc(len + 1);
1031 memcpy(tmp, (char *)s, len);
1032 tmp[len] = '\0';
1033
1034 Z_LVAL(ent->data) = php_parse_date(tmp, NULL);
1035
1036 if (Z_LVAL(ent->data) == -1) {
1037 ZVAL_STRINGL(&ent->data, (char *)s, len);
1038 }
1039 efree(tmp);
1040 }
1041 break;
1042
1043 default:
1044 break;
1045 }
1046 }
1047 }
1048
1049
1050
1051
1052 int php_wddx_deserialize_ex(const char *value, size_t vallen, zval *return_value)
1053 {
1054 wddx_stack stack;
1055 XML_Parser parser;
1056 st_entry *ent;
1057 int retval;
1058
1059 wddx_stack_init(&stack);
1060 parser = XML_ParserCreate((XML_Char *) "UTF-8");
1061
1062 XML_SetUserData(parser, &stack);
1063 XML_SetElementHandler(parser, php_wddx_push_element, php_wddx_pop_element);
1064 XML_SetCharacterDataHandler(parser, php_wddx_process_data);
1065
1066
1067 XML_Parse(parser, (const XML_Char *) value, (int)vallen, 1);
1068
1069 XML_ParserFree(parser);
1070
1071 if (stack.top == 1) {
1072 wddx_stack_top(&stack, (void**)&ent);
1073 ZVAL_COPY(return_value, &ent->data);
1074 retval = SUCCESS;
1075 } else {
1076 retval = FAILURE;
1077 }
1078
1079 wddx_stack_destroy(&stack);
1080
1081 return retval;
1082 }
1083
1084
1085
1086
1087 PHP_FUNCTION(wddx_serialize_value)
1088 {
1089 zval *var;
1090 char *comment = NULL;
1091 size_t comment_len = 0;
1092 wddx_packet *packet;
1093
1094 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|s", &var, &comment, &comment_len) == FAILURE) {
1095 return;
1096 }
1097
1098 packet = php_wddx_constructor();
1099
1100 php_wddx_packet_start(packet, comment, comment_len);
1101 php_wddx_serialize_var(packet, var, NULL);
1102 php_wddx_packet_end(packet);
1103 smart_str_0(packet);
1104
1105 RETVAL_STR_COPY(packet->s);
1106 php_wddx_destructor(packet);
1107 }
1108
1109
1110
1111
1112 PHP_FUNCTION(wddx_serialize_vars)
1113 {
1114 int num_args, i;
1115 wddx_packet *packet;
1116 zval *args = NULL;
1117
1118 if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &num_args) == FAILURE) {
1119 return;
1120 }
1121
1122 packet = php_wddx_constructor();
1123
1124 php_wddx_packet_start(packet, NULL, 0);
1125 php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
1126
1127 for (i=0; i<num_args; i++) {
1128 zval *arg;
1129 if (!Z_ISREF(args[i])) {
1130 arg = &args[i];
1131 } else {
1132 arg = Z_REFVAL(args[i]);
1133 }
1134 if (Z_TYPE_P(arg) != IS_ARRAY && Z_TYPE_P(arg) != IS_OBJECT) {
1135 convert_to_string_ex(arg);
1136 }
1137 php_wddx_add_var(packet, arg);
1138 }
1139
1140 php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
1141 php_wddx_packet_end(packet);
1142 smart_str_0(packet);
1143
1144 RETVAL_STR_COPY(packet->s);
1145 php_wddx_destructor(packet);
1146 }
1147
1148
1149
1150
1151 wddx_packet *php_wddx_constructor(void)
1152 {
1153 smart_str *packet;
1154
1155 packet = ecalloc(1, sizeof(smart_str));
1156
1157 return packet;
1158 }
1159
1160
1161
1162
1163 void php_wddx_destructor(wddx_packet *packet)
1164 {
1165 smart_str_free(packet);
1166 efree(packet);
1167 }
1168
1169
1170
1171
1172 PHP_FUNCTION(wddx_packet_start)
1173 {
1174 char *comment = NULL;
1175 size_t comment_len = 0;
1176 wddx_packet *packet;
1177
1178 comment = NULL;
1179
1180 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &comment, &comment_len) == FAILURE) {
1181 return;
1182 }
1183
1184 packet = php_wddx_constructor();
1185
1186 php_wddx_packet_start(packet, comment, comment_len);
1187 php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
1188
1189 RETURN_RES(zend_register_resource(packet, le_wddx));
1190 }
1191
1192
1193
1194
1195 PHP_FUNCTION(wddx_packet_end)
1196 {
1197 zval *packet_id;
1198 wddx_packet *packet = NULL;
1199
1200 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &packet_id) == FAILURE) {
1201 return;
1202 }
1203
1204 if ((packet = (wddx_packet *)zend_fetch_resource(Z_RES_P(packet_id), "WDDX packet ID", le_wddx)) == NULL) {
1205 RETURN_FALSE;
1206 }
1207
1208 php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
1209
1210 php_wddx_packet_end(packet);
1211 smart_str_0(packet);
1212
1213 RETVAL_STR_COPY(packet->s);
1214
1215 zend_list_close(Z_RES_P(packet_id));
1216 }
1217
1218
1219
1220
1221 PHP_FUNCTION(wddx_add_vars)
1222 {
1223 int num_args, i;
1224 zval *args = NULL;
1225 zval *packet_id;
1226 wddx_packet *packet = NULL;
1227
1228 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r+", &packet_id, &args, &num_args) == FAILURE) {
1229 return;
1230 }
1231
1232 if ((packet = (wddx_packet *)zend_fetch_resource(Z_RES_P(packet_id), "WDDX packet ID", le_wddx)) == NULL) {
1233 RETURN_FALSE;
1234 }
1235
1236 for (i=0; i<num_args; i++) {
1237 zval *arg;
1238 if (!Z_ISREF(args[i])) {
1239 arg = &args[i];
1240 } else {
1241 arg = Z_REFVAL(args[i]);
1242 }
1243 if (Z_TYPE_P(arg) != IS_ARRAY && Z_TYPE_P(arg) != IS_OBJECT) {
1244 convert_to_string_ex(arg);
1245 }
1246 php_wddx_add_var(packet, arg);
1247 }
1248
1249 RETURN_TRUE;
1250 }
1251
1252
1253
1254
1255 PHP_FUNCTION(wddx_deserialize)
1256 {
1257 zval *packet;
1258 php_stream *stream = NULL;
1259 zend_string *payload = NULL;
1260
1261 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &packet) == FAILURE) {
1262 return;
1263 }
1264
1265 if (Z_TYPE_P(packet) == IS_STRING) {
1266 payload = Z_STR_P(packet);
1267 } else if (Z_TYPE_P(packet) == IS_RESOURCE) {
1268 php_stream_from_zval(stream, packet);
1269 if (stream) {
1270 payload = php_stream_copy_to_mem(stream, PHP_STREAM_COPY_ALL, 0);
1271 }
1272 } else {
1273 php_error_docref(NULL, E_WARNING, "Expecting parameter 1 to be a string or a stream");
1274 return;
1275 }
1276
1277 if (payload == NULL) {
1278 return;
1279 }
1280
1281 php_wddx_deserialize_ex(ZSTR_VAL(payload), ZSTR_LEN(payload), return_value);
1282
1283 if (stream) {
1284 efree(payload);
1285 }
1286 }
1287
1288
1289 #endif
1290
1291
1292
1293
1294
1295
1296
1297
1298