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