wddx.c 33 KB

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