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