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 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include "php.h"
28
29 #if HAVE_WDDX
30
31 #include "ext/xml/expat_compat.h"
32 #include "php_wddx.h"
33 #include "php_wddx_api.h"
34
35 #define PHP_XML_INTERNAL
36 #include "ext/xml/php_xml.h"
37 #include "ext/standard/php_incomplete_class.h"
38 #include "ext/standard/base64.h"
39 #include "ext/standard/info.h"
40 #include "zend_smart_str.h"
41 #include "ext/standard/html.h"
42 #include "ext/standard/php_string.h"
43 #include "ext/date/php_date.h"
44 #include "zend_globals.h"
45
46 #define WDDX_BUF_LEN 256
47 #define PHP_CLASS_NAME_VAR "php_class_name"
48
49 #define EL_ARRAY "array"
50 #define EL_BINARY "binary"
51 #define EL_BOOLEAN "boolean"
52 #define EL_CHAR "char"
53 #define EL_CHAR_CODE "code"
54 #define EL_NULL "null"
55 #define EL_NUMBER "number"
56 #define EL_PACKET "wddxPacket"
57 #define EL_STRING "string"
58 #define EL_STRUCT "struct"
59 #define EL_VALUE "value"
60 #define EL_VAR "var"
61 #define EL_NAME "name"
62 #define EL_VERSION "version"
63 #define EL_RECORDSET "recordset"
64 #define EL_FIELD "field"
65 #define EL_DATETIME "dateTime"
66
67 #define php_wddx_deserialize(a,b) \
68 php_wddx_deserialize_ex(Z_STRVAL_P(a), Z_STRLEN_P(a), (b))
69
70 #define SET_STACK_VARNAME \
71 if (stack->varname) { \
72 ent.varname = estrdup(stack->varname); \
73 efree(stack->varname); \
74 stack->varname = NULL; \
75 } else \
76 ent.varname = NULL; \
77
78 static int le_wddx;
79
80 typedef struct {
81 zval data;
82 enum {
83 ST_ARRAY,
84 ST_BOOLEAN,
85 ST_NULL,
86 ST_NUMBER,
87 ST_STRING,
88 ST_BINARY,
89 ST_STRUCT,
90 ST_RECORDSET,
91 ST_FIELD,
92 ST_DATETIME
93 } type;
94 char *varname;
95 } st_entry;
96
97 typedef struct {
98 int top, max;
99 char *varname;
100 zend_bool done;
101 void **elements;
102 } wddx_stack;
103
104
105 static void php_wddx_process_data(void *user_data, const XML_Char *s, int len);
106
107 /* {{{ arginfo */
108 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_serialize_value, 0, 0, 1)
109 ZEND_ARG_INFO(0, var)
110 ZEND_ARG_INFO(0, comment)
111 ZEND_END_ARG_INFO()
112
113 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_serialize_vars, 0, 0, 1)
114 ZEND_ARG_VARIADIC_INFO(0, var_names)
115 ZEND_END_ARG_INFO()
116
117 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_serialize_start, 0, 0, 0)
118 ZEND_ARG_INFO(0, comment)
119 ZEND_END_ARG_INFO()
120
121 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_packet_end, 0, 0, 1)
122 ZEND_ARG_INFO(0, packet_id)
123 ZEND_END_ARG_INFO()
124
125 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_add_vars, 0, 0, 2)
126 ZEND_ARG_INFO(0, packet_id)
127 ZEND_ARG_VARIADIC_INFO(0, var_names)
128 ZEND_END_ARG_INFO()
129
130 ZEND_BEGIN_ARG_INFO_EX(arginfo_wddx_deserialize, 0, 0, 1)
131 ZEND_ARG_INFO(0, packet)
132 ZEND_END_ARG_INFO()
133 /* }}} */
134
135 /* {{{ wddx_functions[]
136 */
137 static const zend_function_entry wddx_functions[] = {
138 PHP_FE(wddx_serialize_value, arginfo_wddx_serialize_value)
139 PHP_FE(wddx_serialize_vars, arginfo_wddx_serialize_vars)
140 PHP_FE(wddx_packet_start, arginfo_wddx_serialize_start)
141 PHP_FE(wddx_packet_end, arginfo_wddx_packet_end)
142 PHP_FE(wddx_add_vars, arginfo_wddx_add_vars)
143 PHP_FE(wddx_deserialize, arginfo_wddx_deserialize)
144 PHP_FE_END
145 };
146 /* }}} */
147
148 PHP_MINIT_FUNCTION(wddx);
149 PHP_MINFO_FUNCTION(wddx);
150
151 /* {{{ dynamically loadable module stuff */
152 #ifdef COMPILE_DL_WDDX
153 ZEND_GET_MODULE(wddx)
154 #endif /* COMPILE_DL_WDDX */
155 /* }}} */
156
157 /* {{{ wddx_module_entry
158 */
159 zend_module_entry wddx_module_entry = {
160 STANDARD_MODULE_HEADER,
161 "wddx",
162 wddx_functions,
163 PHP_MINIT(wddx),
164 NULL,
165 NULL,
166 NULL,
167 PHP_MINFO(wddx),
168 PHP_WDDX_VERSION,
169 STANDARD_MODULE_PROPERTIES
170 };
171 /* }}} */
172
173 /* {{{ wddx_stack_init
174 */
wddx_stack_init(wddx_stack * stack)175 static int wddx_stack_init(wddx_stack *stack)
176 {
177 stack->top = 0;
178 stack->elements = (void **) safe_emalloc(sizeof(void **), STACK_BLOCK_SIZE, 0);
179 stack->max = STACK_BLOCK_SIZE;
180 stack->varname = NULL;
181 stack->done = 0;
182
183 return SUCCESS;
184 }
185 /* }}} */
186
187 /* {{{ wddx_stack_push
188 */
wddx_stack_push(wddx_stack * stack,void * element,int size)189 static int wddx_stack_push(wddx_stack *stack, void *element, int size)
190 {
191 if (stack->top >= stack->max) { /* we need to allocate more memory */
192 stack->elements = (void **) erealloc(stack->elements,
193 (sizeof(void **) * (stack->max += STACK_BLOCK_SIZE)));
194 }
195 stack->elements[stack->top] = (void *) emalloc(size);
196 memcpy(stack->elements[stack->top], element, size);
197 return stack->top++;
198 }
199 /* }}} */
200
201 /* {{{ wddx_stack_top
202 */
wddx_stack_top(wddx_stack * stack,void ** element)203 static int wddx_stack_top(wddx_stack *stack, void **element)
204 {
205 if (stack->top > 0) {
206 *element = stack->elements[stack->top - 1];
207 return SUCCESS;
208 } else {
209 *element = NULL;
210 return FAILURE;
211 }
212 }
213 /* }}} */
214
215 /* {{{ wddx_stack_is_empty
216 */
wddx_stack_is_empty(wddx_stack * stack)217 static int wddx_stack_is_empty(wddx_stack *stack)
218 {
219 if (stack->top == 0) {
220 return 1;
221 } else {
222 return 0;
223 }
224 }
225 /* }}} */
226
227 /* {{{ wddx_stack_destroy
228 */
wddx_stack_destroy(wddx_stack * stack)229 static int wddx_stack_destroy(wddx_stack *stack)
230 {
231 register int i;
232
233 if (stack->elements) {
234 for (i = 0; i < stack->top; i++) {
235 if (Z_TYPE(((st_entry *)stack->elements[i])->data) != IS_UNDEF
236 && ((st_entry *)stack->elements[i])->type != ST_FIELD) {
237 zval_ptr_dtor(&((st_entry *)stack->elements[i])->data);
238 }
239 if (((st_entry *)stack->elements[i])->varname) {
240 efree(((st_entry *)stack->elements[i])->varname);
241 }
242 efree(stack->elements[i]);
243 }
244 efree(stack->elements);
245 }
246 if (stack->varname) {
247 efree(stack->varname);
248 }
249 return SUCCESS;
250 }
251 /* }}} */
252
253 /* {{{ release_wddx_packet_rsrc
254 */
release_wddx_packet_rsrc(zend_resource * rsrc)255 static void release_wddx_packet_rsrc(zend_resource *rsrc)
256 {
257 smart_str *str = (smart_str *)rsrc->ptr;
258 smart_str_free(str);
259 efree(str);
260 }
261 /* }}} */
262
263 #include "ext/session/php_session.h"
264
265 #if HAVE_PHP_SESSION
266 /* {{{ PS_SERIALIZER_ENCODE_FUNC
267 */
PS_SERIALIZER_ENCODE_FUNC(wddx)268 PS_SERIALIZER_ENCODE_FUNC(wddx)
269 {
270 wddx_packet *packet;
271 zend_string *str;
272 PS_ENCODE_VARS;
273
274 packet = php_wddx_constructor();
275
276 php_wddx_packet_start(packet, NULL, 0);
277 php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
278
279 PS_ENCODE_LOOP(
280 php_wddx_serialize_var(packet, struc, key);
281 );
282
283 php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
284 php_wddx_packet_end(packet);
285 smart_str_0(packet);
286 str = zend_string_copy(packet->s);
287 php_wddx_destructor(packet);
288
289 return str;
290 }
291 /* }}} */
292
293 /* {{{ PS_SERIALIZER_DECODE_FUNC
294 */
PS_SERIALIZER_DECODE_FUNC(wddx)295 PS_SERIALIZER_DECODE_FUNC(wddx)
296 {
297 zval retval;
298 zval *ent;
299 zend_string *key;
300 zend_ulong idx;
301 int ret;
302
303 if (vallen == 0) {
304 return SUCCESS;
305 }
306
307 ZVAL_UNDEF(&retval);
308 if ((ret = php_wddx_deserialize_ex(val, vallen, &retval)) == SUCCESS) {
309 if (Z_TYPE(retval) != IS_ARRAY) {
310 zval_ptr_dtor_nogc(&retval);
311 return FAILURE;
312 }
313 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL(retval), idx, key, ent) {
314 if (key == NULL) {
315 key = zend_long_to_str(idx);
316 } else {
317 zend_string_addref(key);
318 }
319 if (php_set_session_var(key, ent, NULL)) {
320 Z_TRY_ADDREF_P(ent);
321 }
322 PS_ADD_VAR(key);
323 zend_string_release_ex(key, 0);
324 } ZEND_HASH_FOREACH_END();
325 }
326
327 zval_ptr_dtor(&retval);
328
329 return ret;
330 }
331 /* }}} */
332 #endif
333
334 /* {{{ PHP_MINIT_FUNCTION
335 */
PHP_MINIT_FUNCTION(wddx)336 PHP_MINIT_FUNCTION(wddx)
337 {
338 le_wddx = zend_register_list_destructors_ex(release_wddx_packet_rsrc, NULL, "wddx", module_number);
339
340 #if HAVE_PHP_SESSION
341 php_session_register_serializer("wddx",
342 PS_SERIALIZER_ENCODE_NAME(wddx),
343 PS_SERIALIZER_DECODE_NAME(wddx));
344 #endif
345
346 return SUCCESS;
347 }
348 /* }}} */
349
350 /* {{{ PHP_MINFO_FUNCTION
351 */
PHP_MINFO_FUNCTION(wddx)352 PHP_MINFO_FUNCTION(wddx)
353 {
354 php_info_print_table_start();
355 #if HAVE_PHP_SESSION
356 php_info_print_table_header(2, "WDDX Support", "enabled" );
357 php_info_print_table_row(2, "WDDX Session Serializer", "enabled" );
358 #else
359 php_info_print_table_row(2, "WDDX Support", "enabled" );
360 #endif
361 php_info_print_table_end();
362 }
363 /* }}} */
364
365 /* {{{ php_wddx_packet_start
366 */
php_wddx_packet_start(wddx_packet * packet,char * comment,size_t comment_len)367 void php_wddx_packet_start(wddx_packet *packet, char *comment, size_t comment_len)
368 {
369 php_wddx_add_chunk_static(packet, WDDX_PACKET_S);
370 if (comment) {
371 zend_string *escaped = php_escape_html_entities(
372 comment, comment_len, 0, ENT_QUOTES, NULL);
373
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, ZSTR_VAL(escaped), ZSTR_LEN(escaped));
377 php_wddx_add_chunk_static(packet, WDDX_COMMENT_E);
378 php_wddx_add_chunk_static(packet, WDDX_HEADER_E);
379
380 zend_string_release_ex(escaped, 0);
381 } else {
382 php_wddx_add_chunk_static(packet, WDDX_HEADER);
383 }
384 php_wddx_add_chunk_static(packet, WDDX_DATA_S);
385 }
386 /* }}} */
387
388 /* {{{ php_wddx_packet_end
389 */
php_wddx_packet_end(wddx_packet * packet)390 void php_wddx_packet_end(wddx_packet *packet)
391 {
392 php_wddx_add_chunk_static(packet, WDDX_DATA_E);
393 php_wddx_add_chunk_static(packet, WDDX_PACKET_E);
394 }
395 /* }}} */
396
397 #define FLUSH_BUF() \
398 if (l > 0) { \
399 php_wddx_add_chunk_ex(packet, buf, l); \
400 l = 0; \
401 }
402
403 /* {{{ php_wddx_serialize_string
404 */
php_wddx_serialize_string(wddx_packet * packet,zval * var)405 static void php_wddx_serialize_string(wddx_packet *packet, zval *var)
406 {
407 php_wddx_add_chunk_static(packet, WDDX_STRING_S);
408
409 if (Z_STRLEN_P(var) > 0) {
410 zend_string *buf = php_escape_html_entities(
411 (unsigned char *) Z_STRVAL_P(var), Z_STRLEN_P(var), 0, ENT_QUOTES, NULL);
412
413 php_wddx_add_chunk_ex(packet, ZSTR_VAL(buf), ZSTR_LEN(buf));
414
415 zend_string_release_ex(buf, 0);
416 }
417 php_wddx_add_chunk_static(packet, WDDX_STRING_E);
418 }
419 /* }}} */
420
421 /* {{{ php_wddx_serialize_number
422 */
php_wddx_serialize_number(wddx_packet * packet,zval * var)423 static void php_wddx_serialize_number(wddx_packet *packet, zval *var)
424 {
425 char tmp_buf[WDDX_BUF_LEN], *dec_point;
426 zend_string *str = zval_get_string_func(var);
427 snprintf(tmp_buf, sizeof(tmp_buf), WDDX_NUMBER, ZSTR_VAL(str));
428 zend_string_release_ex(str, 0);
429
430 dec_point = strchr(tmp_buf, ',');
431 if (dec_point) {
432 *dec_point = '.';
433 }
434 php_wddx_add_chunk(packet, tmp_buf);
435 }
436 /* }}} */
437
438 /* {{{ php_wddx_serialize_boolean
439 */
php_wddx_serialize_boolean(wddx_packet * packet,zval * var)440 static void php_wddx_serialize_boolean(wddx_packet *packet, zval *var)
441 {
442 php_wddx_add_chunk(packet, Z_TYPE_P(var) == IS_TRUE ? WDDX_BOOLEAN_TRUE : WDDX_BOOLEAN_FALSE);
443 }
444 /* }}} */
445
446 /* {{{ php_wddx_serialize_unset
447 */
php_wddx_serialize_unset(wddx_packet * packet)448 static void php_wddx_serialize_unset(wddx_packet *packet)
449 {
450 php_wddx_add_chunk_static(packet, WDDX_NULL);
451 }
452 /* }}} */
453
454 /* {{{ php_wddx_serialize_object
455 */
php_wddx_serialize_object(wddx_packet * packet,zval * obj)456 static void php_wddx_serialize_object(wddx_packet *packet, zval *obj)
457 {
458 /* OBJECTS_FIXME */
459 zval *ent, fname, *varname;
460 zval retval;
461 zend_string *key;
462 zend_ulong idx;
463 char tmp_buf[WDDX_BUF_LEN];
464 HashTable *objhash, *sleephash;
465 zend_class_entry *ce;
466 PHP_CLASS_ATTRIBUTES;
467
468 PHP_SET_CLASS_ATTRIBUTES(obj);
469 ce = Z_OBJCE_P(obj);
470 if (!ce || ce->serialize || ce->unserialize) {
471 php_error_docref(NULL, E_WARNING, "Class %s can not be serialized", ZSTR_VAL(class_name));
472 PHP_CLEANUP_CLASS_ATTRIBUTES();
473 return;
474 }
475
476 ZVAL_STRING(&fname, "__sleep");
477 /*
478 * We try to call __sleep() method on object. It's supposed to return an
479 * array of property names to be serialized.
480 */
481 if (call_user_function(CG(function_table), obj, &fname, &retval, 0, 0) == SUCCESS) {
482 if (!Z_ISUNDEF(retval) && (sleephash = HASH_OF(&retval))) {
483 php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
484 snprintf(tmp_buf, WDDX_BUF_LEN, WDDX_VAR_S, PHP_CLASS_NAME_VAR);
485 php_wddx_add_chunk(packet, tmp_buf);
486 php_wddx_add_chunk_static(packet, WDDX_STRING_S);
487 php_wddx_add_chunk_ex(packet, ZSTR_VAL(class_name), ZSTR_LEN(class_name));
488 php_wddx_add_chunk_static(packet, WDDX_STRING_E);
489 php_wddx_add_chunk_static(packet, WDDX_VAR_E);
490
491 objhash = Z_OBJPROP_P(obj);
492
493 ZEND_HASH_FOREACH_VAL(sleephash, varname) {
494 if (Z_TYPE_P(varname) != IS_STRING) {
495 php_error_docref(NULL, E_NOTICE, "__sleep should return an array only containing the names of instance-variables to serialize.");
496 continue;
497 }
498
499 if ((ent = zend_hash_find(objhash, Z_STR_P(varname))) != NULL) {
500 php_wddx_serialize_var(packet, ent, Z_STR_P(varname));
501 }
502 } ZEND_HASH_FOREACH_END();
503
504 php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
505 }
506 } else {
507 php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
508 snprintf(tmp_buf, WDDX_BUF_LEN, WDDX_VAR_S, PHP_CLASS_NAME_VAR);
509 php_wddx_add_chunk(packet, tmp_buf);
510 php_wddx_add_chunk_static(packet, WDDX_STRING_S);
511 php_wddx_add_chunk_ex(packet, ZSTR_VAL(class_name), ZSTR_LEN(class_name));
512 php_wddx_add_chunk_static(packet, WDDX_STRING_E);
513 php_wddx_add_chunk_static(packet, WDDX_VAR_E);
514
515 objhash = Z_OBJPROP_P(obj);
516 ZEND_HASH_FOREACH_KEY_VAL(objhash, idx, key, ent) {
517 if (ent == obj) {
518 continue;
519 }
520 if (key) {
521 const char *class_name, *prop_name;
522 size_t prop_name_len;
523 zend_string *tmp;
524
525 zend_unmangle_property_name_ex(key, &class_name, &prop_name, &prop_name_len);
526 tmp = zend_string_init(prop_name, prop_name_len, 0);
527 php_wddx_serialize_var(packet, ent, tmp);
528 zend_string_release_ex(tmp, 0);
529 } else {
530 key = zend_long_to_str(idx);
531 php_wddx_serialize_var(packet, ent, key);
532 zend_string_release_ex(key, 0);
533 }
534 } ZEND_HASH_FOREACH_END();
535 php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
536 }
537
538 PHP_CLEANUP_CLASS_ATTRIBUTES();
539
540 zval_ptr_dtor(&fname);
541 zval_ptr_dtor(&retval);
542 }
543 /* }}} */
544
545 /* {{{ php_wddx_serialize_array
546 */
php_wddx_serialize_array(wddx_packet * packet,zval * arr)547 static void php_wddx_serialize_array(wddx_packet *packet, zval *arr)
548 {
549 zval *ent;
550 zend_string *key;
551 int is_struct = 0;
552 zend_ulong idx;
553 HashTable *target_hash;
554 char tmp_buf[WDDX_BUF_LEN];
555 zend_ulong ind = 0;
556
557 target_hash = Z_ARRVAL_P(arr);
558 ZEND_HASH_FOREACH_KEY(target_hash, idx, key) {
559 if (key) {
560 is_struct = 1;
561 break;
562 }
563
564 if (idx != ind) {
565 is_struct = 1;
566 break;
567 }
568 ind++;
569 } ZEND_HASH_FOREACH_END();
570
571 if (is_struct) {
572 php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
573 } else {
574 snprintf(tmp_buf, sizeof(tmp_buf), WDDX_ARRAY_S, zend_hash_num_elements(target_hash));
575 php_wddx_add_chunk(packet, tmp_buf);
576 }
577
578 ZEND_HASH_FOREACH_KEY_VAL(target_hash, idx, key, ent) {
579 if (ent == arr) {
580 continue;
581 }
582
583 if (is_struct) {
584 if (key) {
585 php_wddx_serialize_var(packet, ent, key);
586 } else {
587 key = zend_long_to_str(idx);
588 php_wddx_serialize_var(packet, ent, key);
589 zend_string_release_ex(key, 0);
590 }
591 } else {
592 php_wddx_serialize_var(packet, ent, NULL);
593 }
594 } ZEND_HASH_FOREACH_END();
595
596 if (is_struct) {
597 php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
598 } else {
599 php_wddx_add_chunk_static(packet, WDDX_ARRAY_E);
600 }
601 }
602 /* }}} */
603
604 /* {{{ php_wddx_serialize_var
605 */
php_wddx_serialize_var(wddx_packet * packet,zval * var,zend_string * name)606 void php_wddx_serialize_var(wddx_packet *packet, zval *var, zend_string *name)
607 {
608 HashTable *ht;
609
610 if (name) {
611 char *tmp_buf;
612 zend_string *name_esc = php_escape_html_entities((unsigned char *) ZSTR_VAL(name), ZSTR_LEN(name), 0, ENT_QUOTES, NULL);
613 tmp_buf = emalloc(ZSTR_LEN(name_esc) + sizeof(WDDX_VAR_S));
614 snprintf(tmp_buf, ZSTR_LEN(name_esc) + sizeof(WDDX_VAR_S), WDDX_VAR_S, ZSTR_VAL(name_esc));
615 php_wddx_add_chunk(packet, tmp_buf);
616 efree(tmp_buf);
617 zend_string_release_ex(name_esc, 0);
618 }
619
620 if (Z_TYPE_P(var) == IS_INDIRECT) {
621 var = Z_INDIRECT_P(var);
622 }
623 ZVAL_DEREF(var);
624 switch (Z_TYPE_P(var)) {
625 case IS_STRING:
626 php_wddx_serialize_string(packet, var);
627 break;
628
629 case IS_LONG:
630 case IS_DOUBLE:
631 php_wddx_serialize_number(packet, var);
632 break;
633
634 case IS_TRUE:
635 case IS_FALSE:
636 php_wddx_serialize_boolean(packet, var);
637 break;
638
639 case IS_NULL:
640 php_wddx_serialize_unset(packet);
641 break;
642
643 case IS_ARRAY:
644 ht = Z_ARRVAL_P(var);
645 if (Z_REFCOUNTED_P(var)) {
646 if (GC_IS_RECURSIVE(ht)) {
647 zend_throw_error(NULL, "WDDX doesn't support circular references");
648 return;
649 }
650 GC_PROTECT_RECURSION(ht);
651 }
652 php_wddx_serialize_array(packet, var);
653 if (Z_REFCOUNTED_P(var)) {
654 GC_UNPROTECT_RECURSION(ht);
655 }
656 break;
657
658 case IS_OBJECT:
659 ht = Z_OBJPROP_P(var);
660 if (GC_IS_RECURSIVE(ht)) {
661 zend_throw_error(NULL, "WDDX doesn't support circular references");
662 return;
663 }
664 GC_PROTECT_RECURSION(ht);
665 php_wddx_serialize_object(packet, var);
666 GC_UNPROTECT_RECURSION(ht);
667 break;
668 }
669
670 if (name) {
671 php_wddx_add_chunk_static(packet, WDDX_VAR_E);
672 }
673 }
674 /* }}} */
675
676 /* {{{ php_wddx_add_var
677 */
php_wddx_add_var(wddx_packet * packet,zval * name_var)678 static void php_wddx_add_var(wddx_packet *packet, zval *name_var)
679 {
680 zval *val;
681 HashTable *target_hash;
682
683 if (Z_TYPE_P(name_var) == IS_STRING) {
684 zend_array *symbol_table = zend_rebuild_symbol_table();
685 if ((val = zend_hash_find(symbol_table, Z_STR_P(name_var))) != NULL) {
686 if (Z_TYPE_P(val) == IS_INDIRECT) {
687 val = Z_INDIRECT_P(val);
688 }
689 php_wddx_serialize_var(packet, val, Z_STR_P(name_var));
690 }
691 } else if (Z_TYPE_P(name_var) == IS_ARRAY || Z_TYPE_P(name_var) == IS_OBJECT) {
692 int is_array = Z_TYPE_P(name_var) == IS_ARRAY;
693
694 target_hash = HASH_OF(name_var);
695
696 if (!Z_REFCOUNTED_P(name_var)) {
697 ZEND_HASH_FOREACH_VAL(target_hash, val) {
698 php_wddx_add_var(packet, val);
699 } ZEND_HASH_FOREACH_END();
700 } else {
701 if (is_array) {
702 if (GC_IS_RECURSIVE(target_hash)) {
703 php_error_docref(NULL, E_WARNING, "recursion detected");
704 return;
705 }
706 GC_PROTECT_RECURSION(target_hash);
707 }
708 ZEND_HASH_FOREACH_VAL(target_hash, val) {
709 ZVAL_DEREF(val);
710 php_wddx_add_var(packet, val);
711
712 } ZEND_HASH_FOREACH_END();
713 if (is_array) {
714 GC_UNPROTECT_RECURSION(target_hash);
715 }
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(NULL, &ent1->data, &fname, &retval, 0, 0);
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 Z_TRY_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_ptr_dtor_str(&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_ex(str, 0);
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