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