1 : /*
2 : This file is part of, or distributed with, libXMLRPC - a C library for
3 : xml-encoded function calls.
4 :
5 : Author: Dan Libby (dan@libby.com)
6 : Epinions.com may be contacted at feedback@epinions-inc.com
7 : */
8 :
9 : /*
10 : Copyright 2001 Epinions, Inc.
11 :
12 : Subject to the following 3 conditions, Epinions, Inc. permits you, free
13 : of charge, to (a) use, copy, distribute, modify, perform and display this
14 : software and associated documentation files (the "Software"), and (b)
15 : permit others to whom the Software is furnished to do so as well.
16 :
17 : 1) The above copyright notice and this permission notice shall be included
18 : without modification in all copies or substantial portions of the
19 : Software.
20 :
21 : 2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
22 : ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
23 : IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
24 : PURPOSE OR NONINFRINGEMENT.
25 :
26 : 3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
27 : SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
28 : OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
29 : NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH
30 : DAMAGES.
31 :
32 : */
33 :
34 : /* auto-generated portions of this file are also subject to the php license */
35 :
36 : /*
37 : +----------------------------------------------------------------------+
38 : | PHP Version 5 |
39 : +----------------------------------------------------------------------+
40 : | Copyright (c) 1997-2008 The PHP Group |
41 : +----------------------------------------------------------------------+
42 : | This source file is subject to version 3.01 of the PHP license, |
43 : | that is bundled with this package in the file LICENSE, and is |
44 : | available through the world-wide-web at the following url: |
45 : | http://www.php.net/license/3_01.txt |
46 : | If you did not receive a copy of the PHP license and are unable to |
47 : | obtain it through the world-wide-web, please send a note to |
48 : | license@php.net so we can mail you a copy immediately. |
49 : +----------------------------------------------------------------------+
50 : | Author: Dan Libby |
51 : +----------------------------------------------------------------------+
52 : */
53 :
54 : /* $Id: xmlrpc-epi-php.c,v 1.39.2.5.2.11 2008/07/18 17:34:07 felipe Exp $ */
55 :
56 : /**********************************************************************
57 : * BUGS: *
58 : * - when calling a php user function, there appears to be no way to *
59 : * distinguish between a return value of null, and no return value *
60 : * at all. The xml serialization layer(s) will then return a value *
61 : * of null, when the right thing may be no value at all. (SOAP) *
62 : **********************************************************************/
63 :
64 : #ifdef HAVE_CONFIG_H
65 : #include "config.h"
66 : #endif
67 :
68 : #include "php.h"
69 : #include "ext/standard/info.h"
70 : #include "php_ini.h"
71 : #include "php_xmlrpc.h"
72 : #include "xmlrpc.h"
73 :
74 : #define PHP_EXT_VERSION "0.51"
75 :
76 : static int le_xmlrpc_server;
77 :
78 : zend_function_entry xmlrpc_functions[] = {
79 : PHP_FE(xmlrpc_encode, NULL)
80 : PHP_FE(xmlrpc_decode, NULL)
81 : PHP_FE(xmlrpc_decode_request, second_arg_force_ref)
82 : PHP_FE(xmlrpc_encode_request, NULL)
83 : PHP_FE(xmlrpc_get_type, NULL)
84 : PHP_FE(xmlrpc_set_type, first_arg_force_ref)
85 : PHP_FE(xmlrpc_is_fault, NULL)
86 : PHP_FE(xmlrpc_server_create, NULL)
87 : PHP_FE(xmlrpc_server_destroy, NULL)
88 : PHP_FE(xmlrpc_server_register_method, NULL)
89 : PHP_FE(xmlrpc_server_call_method, NULL)
90 : PHP_FE(xmlrpc_parse_method_descriptions, NULL)
91 : PHP_FE(xmlrpc_server_add_introspection_data, NULL)
92 : PHP_FE(xmlrpc_server_register_introspection_callback, NULL)
93 : {NULL, NULL, NULL}
94 : };
95 :
96 : zend_module_entry xmlrpc_module_entry = {
97 : STANDARD_MODULE_HEADER,
98 : "xmlrpc",
99 : xmlrpc_functions,
100 : PHP_MINIT(xmlrpc),
101 : NULL,
102 : NULL,
103 : NULL,
104 : PHP_MINFO(xmlrpc),
105 : PHP_EXT_VERSION,
106 : STANDARD_MODULE_PROPERTIES
107 : };
108 :
109 : #ifdef COMPILE_DL_XMLRPC
110 : ZEND_GET_MODULE(xmlrpc)
111 : # ifdef PHP_WIN32
112 : # include "zend_arg_defs.c"
113 : # endif
114 : #endif
115 :
116 : /*******************************
117 : * local structures and defines *
118 : *******************************/
119 :
120 : /* per server data */
121 : typedef struct _xmlrpc_server_data {
122 : zval* method_map;
123 : zval* introspection_map;
124 : XMLRPC_SERVER server_ptr;
125 : } xmlrpc_server_data;
126 :
127 :
128 : /* how to format output */
129 : typedef struct _php_output_options {
130 : int b_php_out;
131 : int b_auto_version;
132 : STRUCT_XMLRPC_REQUEST_OUTPUT_OPTIONS xmlrpc_out;
133 : } php_output_options;
134 :
135 : /* data passed to C callback */
136 : typedef struct _xmlrpc_callback_data {
137 : zval* xmlrpc_method;
138 : zval* php_function;
139 : zval* caller_params;
140 : zval* return_data;
141 : xmlrpc_server_data* server;
142 : char php_executed;
143 : } xmlrpc_callback_data;
144 :
145 : /* output options */
146 : #define OUTPUT_TYPE_KEY "output_type"
147 : #define OUTPUT_TYPE_KEY_LEN (sizeof(OUTPUT_TYPE_KEY) - 1)
148 : #define OUTPUT_TYPE_VALUE_PHP "php"
149 : #define OUTPUT_TYPE_VALUE_XML "xml"
150 :
151 : #define VERBOSITY_KEY "verbosity"
152 : #define VERBOSITY_KEY_LEN (sizeof(VERBOSITY_KEY) - 1)
153 : #define VERBOSITY_VALUE_NO_WHITE_SPACE "no_white_space"
154 : #define VERBOSITY_VALUE_NEWLINES_ONLY "newlines_only"
155 : #define VERBOSITY_VALUE_PRETTY "pretty"
156 :
157 : #define ESCAPING_KEY "escaping"
158 : #define ESCAPING_KEY_LEN (sizeof(ESCAPING_KEY) - 1)
159 : #define ESCAPING_VALUE_CDATA "cdata"
160 : #define ESCAPING_VALUE_NON_ASCII "non-ascii"
161 : #define ESCAPING_VALUE_NON_PRINT "non-print"
162 : #define ESCAPING_VALUE_MARKUP "markup"
163 :
164 : #define VERSION_KEY "version"
165 : #define VERSION_KEY_LEN (sizeof(VERSION_KEY) - 1)
166 : #define VERSION_VALUE_SIMPLE "simple"
167 : #define VERSION_VALUE_XMLRPC "xmlrpc"
168 : #define VERSION_VALUE_SOAP11 "soap 1.1"
169 : #define VERSION_VALUE_AUTO "auto"
170 :
171 : #define ENCODING_KEY "encoding"
172 : #define ENCODING_KEY_LEN (sizeof(ENCODING_KEY) - 1)
173 : #define ENCODING_DEFAULT "iso-8859-1"
174 :
175 : /* value types */
176 : #define OBJECT_TYPE_ATTR "xmlrpc_type"
177 : #define OBJECT_VALUE_ATTR "scalar"
178 : #define OBJECT_VALUE_TS_ATTR "timestamp"
179 :
180 : /* faults */
181 : #define FAULT_CODE "faultCode"
182 : #define FAULT_CODE_LEN (sizeof(FAULT_CODE) - 1)
183 : #define FAULT_STRING "faultString"
184 : #define FAULT_STRING_LEN (sizeof(FAULT_STRING) - 1)
185 :
186 : /***********************
187 : * forward declarations *
188 : ***********************/
189 : XMLRPC_VALUE_TYPE get_zval_xmlrpc_type(zval* value, zval** newvalue);
190 : static void php_xmlrpc_introspection_callback(XMLRPC_SERVER server, void* data);
191 : int sset_zval_xmlrpc_type(zval* value, XMLRPC_VALUE_TYPE type);
192 : zval* decode_request_worker(zval* xml_in, zval* encoding_in, zval* method_name_out);
193 : const char* xmlrpc_type_as_str(XMLRPC_VALUE_TYPE type, XMLRPC_VECTOR_TYPE vtype);
194 : XMLRPC_VALUE_TYPE xmlrpc_str_as_type(const char* str);
195 : XMLRPC_VECTOR_TYPE xmlrpc_str_as_vector_type(const char* str);
196 : int set_zval_xmlrpc_type(zval* value, XMLRPC_VALUE_TYPE type);
197 :
198 : /*********************
199 : * startup / shutdown *
200 : *********************/
201 :
202 : static void destroy_server_data(xmlrpc_server_data *server)
203 3 : {
204 3 : if (server) {
205 3 : XMLRPC_ServerDestroy(server->server_ptr);
206 :
207 3 : zval_dtor(server->method_map);
208 3 : FREE_ZVAL(server->method_map);
209 :
210 3 : zval_dtor(server->introspection_map);
211 3 : FREE_ZVAL(server->introspection_map);
212 :
213 3 : efree(server);
214 : }
215 3 : }
216 :
217 : /* called when server is being destructed. either when xmlrpc_server_destroy
218 : * is called, or when request ends. */
219 : static void xmlrpc_server_destructor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
220 3 : {
221 3 : if (rsrc && rsrc->ptr) {
222 3 : destroy_server_data((xmlrpc_server_data*) rsrc->ptr);
223 : }
224 3 : }
225 :
226 : /* module init */
227 : PHP_MINIT_FUNCTION(xmlrpc)
228 9669 : {
229 9669 : le_xmlrpc_server = zend_register_list_destructors_ex(xmlrpc_server_destructor, NULL, "xmlrpc server", module_number);
230 :
231 9669 : return SUCCESS;
232 : }
233 :
234 : /* display info in phpinfo() */
235 : PHP_MINFO_FUNCTION(xmlrpc)
236 5 : {
237 5 : php_info_print_table_start();
238 5 : php_info_print_table_row(2, "core library version", XMLRPC_GetVersionString());
239 5 : php_info_print_table_row(2, "php extension version", PHP_EXT_VERSION);
240 5 : php_info_print_table_row(2, "author", "Dan Libby");
241 5 : php_info_print_table_row(2, "homepage", "http://xmlrpc-epi.sourceforge.net");
242 5 : php_info_print_table_row(2, "open sourced by", "Epinions.com");
243 5 : php_info_print_table_end();
244 5 : }
245 :
246 : /*******************
247 : * random utilities *
248 : *******************/
249 :
250 : /* Utility functions for adding data types to arrays, with or without key (assoc, non-assoc).
251 : * Could easily be further generalized to work with objects.
252 : */
253 : #if 0
254 : static int add_long(zval* list, char* id, int num) {
255 : if(id) return add_assoc_long(list, id, num);
256 : else return add_next_index_long(list, num);
257 : }
258 :
259 : static int add_double(zval* list, char* id, double num) {
260 : if(id) return add_assoc_double(list, id, num);
261 : else return add_next_index_double(list, num);
262 : }
263 :
264 : static int add_string(zval* list, char* id, char* string, int duplicate) {
265 : if(id) return add_assoc_string(list, id, string, duplicate);
266 : else return add_next_index_string(list, string, duplicate);
267 : }
268 :
269 : static int add_stringl(zval* list, char* id, char* string, uint length, int duplicate) {
270 : if(id) return add_assoc_stringl(list, id, string, length, duplicate);
271 : else return add_next_index_stringl(list, string, length, duplicate);
272 : }
273 :
274 : #endif
275 :
276 : static int add_zval(zval* list, const char* id, zval** val)
277 13 : {
278 13 : if (list && val) {
279 13 : if (id) {
280 3 : int id_len = strlen(id);
281 3 : if (!(id_len > 1 && id[0] == '0') && is_numeric_string((char *)id, id_len, NULL, NULL, 0) == IS_LONG) {
282 2 : long index = strtol(id, NULL, 0);
283 2 : return zend_hash_index_update(Z_ARRVAL_P(list), index, (void *) val, sizeof(zval **), NULL);
284 : } else {
285 1 : return zend_hash_update(Z_ARRVAL_P(list), (char*) id, strlen(id) + 1, (void *) val, sizeof(zval **), NULL);
286 : }
287 : } else {
288 10 : return zend_hash_next_index_insert(Z_ARRVAL_P(list), (void *) val, sizeof(zval **), NULL);
289 : }
290 : }
291 : /* what is the correct return on error? */
292 0 : return 0;
293 : }
294 :
295 : #define my_zend_hash_get_current_key(ht, my_key, num_index) zend_hash_get_current_key(ht, my_key, num_index, 0)
296 :
297 :
298 : /*************************
299 : * input / output options *
300 : *************************/
301 :
302 : /* parse an array (user input) into output options suitable for use by xmlrpc engine
303 : * and determine whether to return data as xml or php vars */
304 : static void set_output_options(php_output_options* options, zval* output_opts)
305 15 : {
306 15 : if (options) {
307 :
308 : /* defaults */
309 15 : options->b_php_out = 0;
310 15 : options->b_auto_version = 1;
311 15 : options->xmlrpc_out.version = xmlrpc_version_1_0;
312 15 : options->xmlrpc_out.xml_elem_opts.encoding = ENCODING_DEFAULT;
313 15 : options->xmlrpc_out.xml_elem_opts.verbosity = xml_elem_pretty;
314 15 : options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_markup_escaping | xml_elem_non_ascii_escaping | xml_elem_non_print_escaping;
315 :
316 15 : if (output_opts && Z_TYPE_P(output_opts) == IS_ARRAY) {
317 : zval** val;
318 :
319 : /* type of output (xml/php) */
320 2 : if (zend_hash_find(Z_ARRVAL_P(output_opts), OUTPUT_TYPE_KEY, OUTPUT_TYPE_KEY_LEN + 1, (void**) &val) == SUCCESS) {
321 2 : if (Z_TYPE_PP(val) == IS_STRING) {
322 2 : if (!strcmp(Z_STRVAL_PP(val), OUTPUT_TYPE_VALUE_PHP)) {
323 0 : options->b_php_out = 1;
324 2 : } else if (!strcmp(Z_STRVAL_PP(val), OUTPUT_TYPE_VALUE_XML)) {
325 2 : options->b_php_out = 0;
326 : }
327 : }
328 : }
329 :
330 : /* verbosity of generated xml */
331 2 : if (zend_hash_find(Z_ARRVAL_P(output_opts), VERBOSITY_KEY, VERBOSITY_KEY_LEN + 1, (void**) &val) == SUCCESS) {
332 0 : if (Z_TYPE_PP(val) == IS_STRING) {
333 0 : if (!strcmp(Z_STRVAL_PP(val), VERBOSITY_VALUE_NO_WHITE_SPACE)) {
334 0 : options->xmlrpc_out.xml_elem_opts.verbosity = xml_elem_no_white_space;
335 0 : } else if (!strcmp(Z_STRVAL_PP(val), VERBOSITY_VALUE_NEWLINES_ONLY)) {
336 0 : options->xmlrpc_out.xml_elem_opts.verbosity = xml_elem_newlines_only;
337 0 : } else if (!strcmp(Z_STRVAL_PP(val), VERBOSITY_VALUE_PRETTY)) {
338 0 : options->xmlrpc_out.xml_elem_opts.verbosity = xml_elem_pretty;
339 : }
340 : }
341 : }
342 :
343 : /* version of xml to output */
344 2 : if (zend_hash_find(Z_ARRVAL_P(output_opts), VERSION_KEY, VERSION_KEY_LEN + 1, (void**) &val) == SUCCESS) {
345 2 : if (Z_TYPE_PP(val) == IS_STRING) {
346 2 : options->b_auto_version = 0;
347 2 : if (!strcmp(Z_STRVAL_PP(val), VERSION_VALUE_XMLRPC)) {
348 2 : options->xmlrpc_out.version = xmlrpc_version_1_0;
349 0 : } else if (!strcmp(Z_STRVAL_PP(val), VERSION_VALUE_SIMPLE)) {
350 0 : options->xmlrpc_out.version = xmlrpc_version_simple;
351 0 : } else if (!strcmp((*val)->value.str.val, VERSION_VALUE_SOAP11)) {
352 0 : options->xmlrpc_out.version = xmlrpc_version_soap_1_1;
353 : } else { /* if(!strcmp((*val)->value.str.val, VERSION_VALUE_AUTO)) { */
354 0 : options->b_auto_version = 1;
355 : }
356 : }
357 : }
358 :
359 : /* encoding code set */
360 2 : if(zend_hash_find(Z_ARRVAL_P(output_opts), ENCODING_KEY, ENCODING_KEY_LEN + 1, (void**)&val) == SUCCESS) {
361 0 : if(Z_TYPE_PP(val) == IS_STRING) {
362 0 : options->xmlrpc_out.xml_elem_opts.encoding = estrdup(Z_STRVAL_PP(val));
363 : }
364 : }
365 :
366 : /* escaping options */
367 2 : if (zend_hash_find(Z_ARRVAL_P(output_opts), ESCAPING_KEY, ESCAPING_KEY_LEN + 1, (void**)&val) == SUCCESS) {
368 : /* multiple values allowed. check if array */
369 0 : if (Z_TYPE_PP(val) == IS_ARRAY) {
370 : zval** iter_val;
371 0 : zend_hash_internal_pointer_reset(Z_ARRVAL_PP(val));
372 0 : options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_no_escaping;
373 : while(1) {
374 0 : if(zend_hash_get_current_data(Z_ARRVAL_PP(val), (void**)&iter_val) == SUCCESS) {
375 0 : if(Z_TYPE_PP(iter_val) == IS_STRING && Z_STRVAL_PP(iter_val)) {
376 0 : if(!strcmp(Z_STRVAL_PP(iter_val), ESCAPING_VALUE_CDATA)) {
377 0 : options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_cdata_escaping;
378 : }
379 0 : else if(!strcmp(Z_STRVAL_PP(iter_val), ESCAPING_VALUE_NON_ASCII)) {
380 0 : options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_non_ascii_escaping;
381 : }
382 0 : else if(!strcmp(Z_STRVAL_PP(iter_val), ESCAPING_VALUE_NON_PRINT)) {
383 0 : options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_non_print_escaping;
384 : }
385 0 : else if(!strcmp(Z_STRVAL_PP(iter_val), ESCAPING_VALUE_MARKUP)) {
386 0 : options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_markup_escaping;
387 : }
388 : }
389 : }
390 : else {
391 0 : break;
392 : }
393 :
394 0 : zend_hash_move_forward(Z_ARRVAL_PP(val));
395 0 : }
396 : }
397 : /* else, check for single value */
398 0 : else if(Z_TYPE_PP(val) == IS_STRING) {
399 0 : if(!strcmp(Z_STRVAL_PP(val), ESCAPING_VALUE_CDATA)) {
400 0 : options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_cdata_escaping;
401 : }
402 0 : else if(!strcmp(Z_STRVAL_PP(val), ESCAPING_VALUE_NON_ASCII)) {
403 0 : options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_non_ascii_escaping;
404 : }
405 0 : else if(!strcmp(Z_STRVAL_PP(val), ESCAPING_VALUE_NON_PRINT)) {
406 0 : options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_non_print_escaping;
407 : }
408 0 : else if(!strcmp(Z_STRVAL_PP(val), ESCAPING_VALUE_MARKUP)) {
409 0 : options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_markup_escaping;
410 : }
411 : }
412 : }
413 : }
414 : }
415 15 : }
416 :
417 :
418 : /******************
419 : * encode / decode *
420 : ******************/
421 :
422 : /* php arrays have no distinction between array and struct types.
423 : * they even allow mixed. Thus, we determine the type by iterating
424 : * through the entire array and figuring out each element.
425 : * room for some optimation here if we stop after a specific # of elements.
426 : */
427 : static XMLRPC_VECTOR_TYPE determine_vector_type (HashTable *ht)
428 11 : {
429 11 : int bArray = 0, bStruct = 0, bMixed = 0;
430 : unsigned long num_index;
431 : char* my_key;
432 :
433 11 : zend_hash_internal_pointer_reset(ht);
434 : while(1) {
435 20 : int res = my_zend_hash_get_current_key(ht, &my_key, &num_index);
436 20 : if(res == HASH_KEY_IS_LONG) {
437 5 : if(bStruct) {
438 1 : bMixed = 1;
439 1 : break;
440 : }
441 4 : bArray = 1;
442 : }
443 15 : else if(res == HASH_KEY_NON_EXISTANT) {
444 10 : break;
445 : }
446 5 : else if(res == HASH_KEY_IS_STRING) {
447 5 : if(bArray) {
448 0 : bMixed = 1;
449 0 : break;
450 : }
451 5 : bStruct = 1;
452 : }
453 :
454 9 : zend_hash_move_forward(ht);
455 9 : }
456 11 : return bMixed ? xmlrpc_vector_mixed : (bStruct ? xmlrpc_vector_struct : xmlrpc_vector_array);
457 : }
458 :
459 : /* recursively convert php values into xmlrpc values */
460 : static XMLRPC_VALUE PHP_to_XMLRPC_worker (const char* key, zval* in_val, int depth TSRMLS_DC)
461 22 : {
462 22 : XMLRPC_VALUE xReturn = NULL;
463 22 : if(in_val) {
464 22 : zval* val = NULL;
465 22 : XMLRPC_VALUE_TYPE type = get_zval_xmlrpc_type(in_val, &val);
466 22 : if(val) {
467 22 : switch(type) {
468 : case xmlrpc_base64:
469 0 : if(Z_TYPE_P(val) == IS_NULL) {
470 0 : xReturn = XMLRPC_CreateValueEmpty();
471 0 : XMLRPC_SetValueID(xReturn, key, 0);
472 : } else {
473 0 : xReturn = XMLRPC_CreateValueBase64(key, Z_STRVAL_P(val), Z_STRLEN_P(val));
474 : }
475 0 : break;
476 : case xmlrpc_datetime:
477 1 : convert_to_string(val);
478 1 : xReturn = XMLRPC_CreateValueDateTime_ISO8601(key, Z_STRVAL_P(val));
479 1 : break;
480 : case xmlrpc_boolean:
481 0 : convert_to_boolean(val);
482 0 : xReturn = XMLRPC_CreateValueBoolean(key, Z_LVAL_P(val));
483 0 : break;
484 : case xmlrpc_int:
485 7 : convert_to_long(val);
486 7 : xReturn = XMLRPC_CreateValueInt(key, Z_LVAL_P(val));
487 7 : break;
488 : case xmlrpc_double:
489 2 : convert_to_double(val);
490 2 : xReturn = XMLRPC_CreateValueDouble(key, Z_DVAL_P(val));
491 2 : break;
492 : case xmlrpc_string:
493 6 : convert_to_string(val);
494 6 : xReturn = XMLRPC_CreateValueString(key, Z_STRVAL_P(val), Z_STRLEN_P(val));
495 6 : break;
496 : case xmlrpc_vector: {
497 : unsigned long num_index;
498 : zval** pIter;
499 : char* my_key;
500 6 : HashTable *ht = NULL;
501 :
502 6 : ht = HASH_OF(val);
503 6 : if (ht && ht->nApplyCount > 1) {
504 0 : php_error_docref(NULL TSRMLS_CC, E_ERROR, "XML-RPC doesn't support circular references");
505 0 : return NULL;
506 : }
507 :
508 6 : convert_to_array(val);
509 6 : xReturn = XMLRPC_CreateVector(key, determine_vector_type(Z_ARRVAL_P(val)));
510 :
511 6 : zend_hash_internal_pointer_reset(Z_ARRVAL_P(val));
512 15 : while(zend_hash_get_current_data(Z_ARRVAL_P(val), (void**)&pIter) == SUCCESS) {
513 3 : int res = my_zend_hash_get_current_key(Z_ARRVAL_P(val), &my_key, &num_index);
514 :
515 3 : switch (res) {
516 : case HASH_KEY_NON_EXISTANT:
517 0 : break;
518 : case HASH_KEY_IS_STRING:
519 : case HASH_KEY_IS_LONG:
520 3 : ht = HASH_OF(*pIter);
521 3 : if (ht) {
522 2 : ht->nApplyCount++;
523 : }
524 3 : if (res == HASH_KEY_IS_LONG) {
525 1 : XMLRPC_AddValueToVector(xReturn, PHP_to_XMLRPC_worker(0, *pIter, depth++ TSRMLS_CC));
526 : } else {
527 2 : XMLRPC_AddValueToVector(xReturn, PHP_to_XMLRPC_worker(my_key, *pIter, depth++ TSRMLS_CC));
528 : }
529 3 : if (ht) {
530 2 : ht->nApplyCount--;
531 : }
532 : break;
533 : }
534 3 : zend_hash_move_forward(Z_ARRVAL_P(val));
535 : }
536 : }
537 : break;
538 : default:
539 : break;
540 : }
541 : }
542 : }
543 22 : return xReturn;
544 : }
545 :
546 : static XMLRPC_VALUE PHP_to_XMLRPC(zval* root_val TSRMLS_DC)
547 19 : {
548 19 : return PHP_to_XMLRPC_worker(NULL, root_val, 0 TSRMLS_CC);
549 : }
550 :
551 : /* recursively convert xmlrpc values into php values */
552 : static zval* XMLRPC_to_PHP(XMLRPC_VALUE el)
553 15 : {
554 15 : zval* elem = NULL;
555 : const char* pStr;
556 :
557 15 : if(el) {
558 15 : XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(el);
559 :
560 15 : MAKE_STD_ZVAL(elem); /* init. very important. spent a frustrating day finding this out. */
561 :
562 15 : switch(type) {
563 : case xmlrpc_empty:
564 0 : Z_TYPE_P(elem) = IS_NULL;
565 0 : break;
566 : case xmlrpc_string:
567 4 : pStr = XMLRPC_GetValueString(el);
568 4 : if(pStr) {
569 4 : Z_STRLEN_P(elem) = XMLRPC_GetValueStringLen(el);
570 4 : Z_STRVAL_P(elem) = estrndup(pStr, Z_STRLEN_P(elem));
571 4 : Z_TYPE_P(elem) = IS_STRING;
572 : }
573 4 : break;
574 : case xmlrpc_int:
575 2 : Z_LVAL_P(elem) = XMLRPC_GetValueInt(el);
576 2 : Z_TYPE_P(elem) = IS_LONG;
577 2 : break;
578 : case xmlrpc_boolean:
579 0 : Z_LVAL_P(elem) = XMLRPC_GetValueBoolean(el);
580 0 : Z_TYPE_P(elem) = IS_BOOL;
581 0 : break;
582 : case xmlrpc_double:
583 0 : Z_DVAL_P(elem) = XMLRPC_GetValueDouble(el);
584 0 : Z_TYPE_P(elem) = IS_DOUBLE;
585 0 : break;
586 : case xmlrpc_datetime:
587 1 : Z_STRLEN_P(elem) = XMLRPC_GetValueStringLen(el);
588 1 : Z_STRVAL_P(elem) = estrndup(XMLRPC_GetValueDateTime_ISO8601(el), Z_STRLEN_P(elem));
589 1 : Z_TYPE_P(elem) = IS_STRING;
590 1 : break;
591 : case xmlrpc_base64:
592 0 : pStr = XMLRPC_GetValueBase64(el);
593 0 : if(pStr) {
594 0 : Z_STRLEN_P(elem) = XMLRPC_GetValueStringLen(el);
595 0 : Z_STRVAL_P(elem) = estrndup(pStr, Z_STRLEN_P(elem));
596 0 : Z_TYPE_P(elem) = IS_STRING;
597 : }
598 0 : break;
599 : case xmlrpc_vector:
600 8 : array_init(elem);
601 : {
602 8 : XMLRPC_VALUE xIter = XMLRPC_VectorRewind(el);
603 :
604 23 : while( xIter ) {
605 7 : zval *val = XMLRPC_to_PHP(xIter);
606 7 : if (val) {
607 7 : add_zval(elem, XMLRPC_GetValueID(xIter), &val);
608 : }
609 7 : xIter = XMLRPC_VectorNext(el);
610 : }
611 : }
612 : break;
613 : default:
614 : break;
615 : }
616 15 : set_zval_xmlrpc_type(elem, type);
617 : }
618 15 : return elem;
619 : }
620 :
621 : /* {{{ proto string xmlrpc_encode_request(string method, mixed params)
622 : Generates XML for a method request */
623 : PHP_FUNCTION(xmlrpc_encode_request)
624 12 : {
625 12 : XMLRPC_REQUEST xRequest = NULL;
626 : zval **method, **vals, **out_opts;
627 : char* outBuf;
628 : php_output_options out;
629 :
630 12 : if (ZEND_NUM_ARGS() < 2 || ZEND_NUM_ARGS() > 3 || (zend_get_parameters_ex(ZEND_NUM_ARGS(), &method, &vals, &out_opts) == FAILURE)) {
631 0 : WRONG_PARAM_COUNT; /* prints/logs a warning and returns */
632 : }
633 :
634 12 : set_output_options(&out, (ZEND_NUM_ARGS() == 3) ? *out_opts : 0);
635 :
636 12 : if(return_value_used) {
637 12 : xRequest = XMLRPC_RequestNew();
638 :
639 12 : if(xRequest) {
640 12 : XMLRPC_RequestSetOutputOptions(xRequest, &out.xmlrpc_out);
641 12 : if (Z_TYPE_PP(method) == IS_NULL) {
642 0 : XMLRPC_RequestSetRequestType(xRequest, xmlrpc_request_response);
643 : } else {
644 12 : convert_to_string_ex(method);
645 12 : XMLRPC_RequestSetMethodName(xRequest, Z_STRVAL_PP(method));
646 12 : XMLRPC_RequestSetRequestType(xRequest, xmlrpc_request_call);
647 : }
648 12 : if (Z_TYPE_PP(vals) != IS_NULL) {
649 12 : XMLRPC_RequestSetData(xRequest, PHP_to_XMLRPC(*vals TSRMLS_CC));
650 : }
651 :
652 12 : outBuf = XMLRPC_REQUEST_ToXML(xRequest, 0);
653 12 : if(outBuf) {
654 12 : RETVAL_STRING(outBuf, 1);
655 12 : free(outBuf);
656 : }
657 12 : XMLRPC_RequestFree(xRequest, 1);
658 : }
659 : }
660 :
661 12 : if (out.xmlrpc_out.xml_elem_opts.encoding != ENCODING_DEFAULT) {
662 0 : efree((char *)out.xmlrpc_out.xml_elem_opts.encoding);
663 : }
664 : }
665 : /* }}} */
666 :
667 : /* {{{ proto string xmlrpc_encode(mixed value)
668 : Generates XML for a PHP value */
669 : PHP_FUNCTION(xmlrpc_encode)
670 6 : {
671 6 : XMLRPC_VALUE xOut = NULL;
672 : zval **arg1;
673 : char *outBuf;
674 :
675 6 : if (ZEND_NUM_ARGS() != 1 || (zend_get_parameters_ex(1, &arg1) == FAILURE)) {
676 0 : WRONG_PARAM_COUNT;
677 : }
678 :
679 6 : if( return_value_used ) {
680 : /* convert native php type to xmlrpc type */
681 6 : xOut = PHP_to_XMLRPC(*arg1 TSRMLS_CC);
682 :
683 : /* generate raw xml from xmlrpc data */
684 6 : outBuf = XMLRPC_VALUE_ToXML(xOut, 0);
685 :
686 6 : if(xOut) {
687 6 : if(outBuf) {
688 6 : RETVAL_STRING(outBuf, 1);
689 6 : free(outBuf);
690 : }
691 : /* cleanup */
692 6 : XMLRPC_CleanupValue(xOut);
693 : }
694 : }
695 : }
696 : /* }}} */
697 :
698 :
699 : zval* decode_request_worker (zval* xml_in, zval* encoding_in, zval* method_name_out)
700 7 : {
701 7 : zval* retval = NULL;
702 : XMLRPC_REQUEST response;
703 7 : STRUCT_XMLRPC_REQUEST_INPUT_OPTIONS opts = {{0}};
704 7 : opts.xml_elem_opts.encoding = encoding_in ? utf8_get_encoding_id_from_string(Z_STRVAL_P(encoding_in)) : ENCODING_DEFAULT;
705 :
706 : /* generate XMLRPC_REQUEST from raw xml */
707 7 : response = XMLRPC_REQUEST_FromXML(Z_STRVAL_P(xml_in), Z_STRLEN_P(xml_in), &opts);
708 7 : if(response) {
709 : /* convert xmlrpc data to native php types */
710 7 : retval = XMLRPC_to_PHP(XMLRPC_RequestGetData(response));
711 :
712 7 : if(XMLRPC_RequestGetRequestType(response) == xmlrpc_request_call) {
713 5 : if(method_name_out) {
714 5 : zval_dtor(method_name_out);
715 5 : Z_TYPE_P(method_name_out) = IS_STRING;
716 5 : Z_STRVAL_P(method_name_out) = estrdup(XMLRPC_RequestGetMethodName(response));
717 5 : Z_STRLEN_P(method_name_out) = strlen(Z_STRVAL_P(method_name_out));
718 : }
719 : }
720 :
721 : /* dust, sweep, and mop */
722 7 : XMLRPC_RequestFree(response, 1);
723 : }
724 7 : return retval;
725 : }
726 :
727 : /* {{{ proto array xmlrpc_decode_request(string xml, string& method [, string encoding])
728 : Decodes XML into native PHP types */
729 : PHP_FUNCTION(xmlrpc_decode_request)
730 5 : {
731 5 : zval **xml, **method, **encoding = NULL;
732 5 : int argc = ZEND_NUM_ARGS();
733 :
734 5 : if (argc < 2 || argc > 3 || (zend_get_parameters_ex(argc, &xml, &method, &encoding) == FAILURE)) {
735 0 : WRONG_PARAM_COUNT;
736 : }
737 :
738 5 : convert_to_string_ex(xml);
739 5 : convert_to_string_ex(method);
740 5 : if(argc == 3) {
741 0 : convert_to_string_ex(encoding);
742 : }
743 :
744 5 : if(return_value_used) {
745 5 : zval* retval = decode_request_worker(*xml, encoding ? *encoding : NULL, *method);
746 5 : if(retval) {
747 5 : *return_value = *retval;
748 5 : FREE_ZVAL(retval);
749 : }
750 : }
751 : }
752 : /* }}} */
753 :
754 :
755 : /* {{{ proto array xmlrpc_decode(string xml [, string encoding])
756 : Decodes XML into native PHP types */
757 : PHP_FUNCTION(xmlrpc_decode)
758 2 : {
759 2 : zval **arg1, **arg2 = NULL;
760 2 : int argc = ZEND_NUM_ARGS();
761 :
762 2 : if (argc < 1 || argc > 2 || (zend_get_parameters_ex(argc, &arg1, &arg2) == FAILURE)) {
763 0 : WRONG_PARAM_COUNT;
764 : }
765 :
766 2 : convert_to_string_ex(arg1);
767 2 : if(argc == 2) {
768 0 : convert_to_string_ex(arg2);
769 : }
770 :
771 2 : if(return_value_used) {
772 2 : zval* retval = decode_request_worker(*arg1, arg2 ? *arg2 : NULL, NULL);
773 2 : if(retval) {
774 2 : *return_value = *retval;
775 2 : FREE_ZVAL(retval);
776 : }
777 : }
778 : }
779 : /* }}} */
780 :
781 :
782 : /*************************
783 : * server related methods *
784 : *************************/
785 :
786 : /* {{{ proto resource xmlrpc_server_create(void)
787 : Creates an xmlrpc server */
788 : PHP_FUNCTION(xmlrpc_server_create)
789 3 : {
790 3 : if(ZEND_NUM_ARGS() != 0) {
791 0 : WRONG_PARAM_COUNT;
792 : }
793 :
794 3 : if(return_value_used) {
795 : zval *method_map, *introspection_map;
796 3 : xmlrpc_server_data *server = emalloc(sizeof(xmlrpc_server_data));
797 3 : MAKE_STD_ZVAL(method_map);
798 3 : MAKE_STD_ZVAL(introspection_map);
799 :
800 3 : array_init(method_map);
801 3 : array_init(introspection_map);
802 :
803 : /* allocate server data. free'd in destroy_server_data() */
804 3 : server->method_map = method_map;
805 3 : server->introspection_map = introspection_map;
806 3 : server->server_ptr = XMLRPC_ServerCreate();
807 :
808 3 : XMLRPC_ServerRegisterIntrospectionCallback(server->server_ptr, php_xmlrpc_introspection_callback);
809 :
810 : /* store for later use */
811 3 : ZEND_REGISTER_RESOURCE(return_value,server, le_xmlrpc_server);
812 : }
813 : }
814 : /* }}} */
815 :
816 : /* {{{ proto int xmlrpc_server_destroy(resource server)
817 : Destroys server resources */
818 : PHP_FUNCTION(xmlrpc_server_destroy)
819 0 : {
820 : zval **arg1;
821 0 : int bSuccess = FAILURE;
822 :
823 0 : if (ZEND_NUM_ARGS() != 1 || (zend_get_parameters_ex(1, &arg1) == FAILURE)) {
824 0 : WRONG_PARAM_COUNT;
825 : }
826 :
827 0 : if(Z_TYPE_PP(arg1) == IS_RESOURCE) {
828 : int type;
829 :
830 0 : xmlrpc_server_data *server = zend_list_find(Z_LVAL_PP(arg1), &type);
831 :
832 0 : if(server && type == le_xmlrpc_server) {
833 0 : bSuccess = zend_list_delete(Z_LVAL_PP(arg1));
834 :
835 : /* called by hashtable destructor
836 : * destroy_server_data(server);
837 : */
838 : }
839 : }
840 0 : RETVAL_LONG(bSuccess == SUCCESS);
841 : }
842 : /* }}} */
843 :
844 :
845 : /* called by xmlrpc C engine as method handler for all registered methods.
846 : * it then calls the corresponding PHP function to handle the method.
847 : */
848 : static XMLRPC_VALUE php_xmlrpc_callback(XMLRPC_SERVER server, XMLRPC_REQUEST xRequest, void* data)
849 1 : {
850 1 : xmlrpc_callback_data* pData = (xmlrpc_callback_data*)data;
851 : zval* xmlrpc_params;
852 : zval* callback_params[3];
853 : TSRMLS_FETCH();
854 :
855 : /* convert xmlrpc to native php types */
856 1 : xmlrpc_params = XMLRPC_to_PHP(XMLRPC_RequestGetData(xRequest));
857 :
858 : /* setup data hoojum */
859 1 : callback_params[0] = pData->xmlrpc_method;
860 1 : callback_params[1] = xmlrpc_params;
861 1 : callback_params[2] = pData->caller_params;
862 :
863 : /* Use same C function for all methods */
864 :
865 : /* php func prototype: function user_func($method_name, $xmlrpc_params, $user_params) */
866 1 : call_user_function(CG(function_table), NULL, pData->php_function, pData->return_data, 3, callback_params TSRMLS_CC);
867 :
868 1 : pData->php_executed = 1;
869 :
870 1 : zval_ptr_dtor(&xmlrpc_params);
871 :
872 1 : return NULL;
873 : }
874 :
875 : /* called by the C server when it first receives an introspection request. We pass this on to
876 : * our PHP listeners, if any
877 : */
878 : static void php_xmlrpc_introspection_callback(XMLRPC_SERVER server, void* data)
879 2 : {
880 : zval retval, **php_function;
881 : zval* callback_params[1];
882 : char *php_function_name;
883 2 : xmlrpc_callback_data* pData = (xmlrpc_callback_data*)data;
884 : TSRMLS_FETCH();
885 :
886 : /* setup data hoojum */
887 2 : callback_params[0] = pData->caller_params;
888 :
889 : /* loop through and call all registered callbacks */
890 2 : zend_hash_internal_pointer_reset(Z_ARRVAL_P(pData->server->introspection_map));
891 : while(1) {
892 7 : if(zend_hash_get_current_data(Z_ARRVAL_P(pData->server->introspection_map), (void**)&php_function) == SUCCESS) {
893 :
894 5 : if (zend_is_callable(*php_function, 0, &php_function_name)) {
895 : /* php func prototype: function string user_func($user_params) */
896 1 : if (call_user_function(CG(function_table), NULL, *php_function, &retval, 1, callback_params TSRMLS_CC) == SUCCESS) {
897 : XMLRPC_VALUE xData;
898 1 : STRUCT_XMLRPC_ERROR err = {0};
899 :
900 : /* return value should be a string */
901 1 : convert_to_string(&retval);
902 :
903 1 : xData = XMLRPC_IntrospectionCreateDescription(Z_STRVAL(retval), &err);
904 :
905 1 : if(xData) {
906 0 : if(!XMLRPC_ServerAddIntrospectionData(server, xData)) {
907 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to add introspection data returned from %s(), improper element structure", php_function_name);
908 : }
909 0 : XMLRPC_CleanupValue(xData);
910 : } else {
911 : /* could not create description */
912 1 : if(err.xml_elem_error.parser_code) {
913 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "xml parse error: [line %ld, column %ld, message: %s] Unable to add introspection data returned from %s()",
914 : err.xml_elem_error.column, err.xml_elem_error.line, err.xml_elem_error.parser_error, php_function_name);
915 : } else {
916 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to add introspection data returned from %s()", php_function_name);
917 : }
918 : }
919 1 : zval_dtor(&retval);
920 : } else {
921 : /* user func failed */
922 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error calling user introspection callback: %s()", php_function_name);
923 : }
924 : } else {
925 4 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid callback '%s' passed", php_function_name);
926 : }
927 5 : efree(php_function_name);
928 : } else {
929 2 : break;
930 : }
931 5 : zend_hash_move_forward(Z_ARRVAL_P(pData->server->introspection_map));
932 5 : }
933 :
934 : /* so we don't call the same callbacks ever again */
935 2 : zend_hash_clean(Z_ARRVAL_P(pData->server->introspection_map));
936 2 : }
937 :
938 : /* {{{ proto bool xmlrpc_server_register_method(resource server, string method_name, string function)
939 : Register a PHP function to handle method matching method_name */
940 : PHP_FUNCTION(xmlrpc_server_register_method)
941 1 : {
942 : zval **method_key, **method_name, **handle, *method_name_save;
943 : int type;
944 : xmlrpc_server_data* server;
945 :
946 1 : if (ZEND_NUM_ARGS() != 3 || (zend_get_parameters_ex(3, &handle, &method_key, &method_name) == FAILURE)) {
947 0 : WRONG_PARAM_COUNT;
948 : }
949 :
950 1 : server = zend_list_find(Z_LVAL_PP(handle), &type);
951 :
952 1 : if(type == le_xmlrpc_server) {
953 : /* register with C engine. every method just calls our standard callback,
954 : * and it then dispatches to php as necessary
955 : */
956 1 : if(XMLRPC_ServerRegisterMethod(server->server_ptr, Z_STRVAL_PP(method_key), php_xmlrpc_callback)) {
957 : /* save for later use */
958 1 : MAKE_STD_ZVAL(method_name_save);
959 1 : *method_name_save = **method_name;
960 1 : zval_copy_ctor(method_name_save);
961 :
962 : /* register our php method */
963 1 : add_zval(server->method_map, Z_STRVAL_PP(method_key), &method_name_save);
964 :
965 1 : RETURN_BOOL(1);
966 : }
967 : }
968 0 : RETURN_BOOL(0);
969 : }
970 : /* }}} */
971 :
972 :
973 : /* {{{ proto bool xmlrpc_server_register_introspection_callback(resource server, string function)
974 : Register a PHP function to generate documentation */
975 : PHP_FUNCTION(xmlrpc_server_register_introspection_callback)
976 5 : {
977 : zval **method_name, **handle, *method_name_save;
978 : int type;
979 : xmlrpc_server_data* server;
980 :
981 5 : if (ZEND_NUM_ARGS() != 2 || (zend_get_parameters_ex(2, &handle, &method_name) == FAILURE)) {
982 0 : WRONG_PARAM_COUNT;
983 : }
984 :
985 5 : server = zend_list_find(Z_LVAL_PP(handle), &type);
986 :
987 5 : if(type == le_xmlrpc_server) {
988 : /* save for later use */
989 5 : MAKE_STD_ZVAL(method_name_save);
990 5 : *method_name_save = **method_name;
991 5 : zval_copy_ctor(method_name_save);
992 :
993 : /* register our php method */
994 5 : add_zval(server->introspection_map, NULL, &method_name_save);
995 :
996 5 : RETURN_BOOL(1);
997 : }
998 0 : RETURN_BOOL(0);
999 : }
1000 : /* }}} */
1001 :
1002 :
1003 : /* this function is itchin for a re-write */
1004 :
1005 : /* {{{ proto mixed xmlrpc_server_call_method(resource server, string xml, mixed user_data [, array output_options])
1006 : Parses XML requests and call methods */
1007 : PHP_FUNCTION(xmlrpc_server_call_method)
1008 3 : {
1009 3 : xmlrpc_callback_data data = {0};
1010 : XMLRPC_REQUEST xRequest;
1011 : STRUCT_XMLRPC_REQUEST_INPUT_OPTIONS input_opts;
1012 : xmlrpc_server_data* server;
1013 3 : zval **rawxml, **caller_params, **handle, **output_opts = NULL;
1014 : int type;
1015 : php_output_options out;
1016 3 : int argc =ZEND_NUM_ARGS();
1017 :
1018 3 : if (argc < 3 || argc > 4 || (zend_get_parameters_ex(argc, &handle, &rawxml, &caller_params, &output_opts) != SUCCESS)) {
1019 0 : WRONG_PARAM_COUNT;
1020 : }
1021 : /* user output options */
1022 3 : if (argc == 3) {
1023 1 : set_output_options(&out, NULL);
1024 : }
1025 : else {
1026 2 : set_output_options(&out, *output_opts);
1027 : }
1028 :
1029 3 : server = zend_list_find(Z_LVAL_PP(handle), &type);
1030 :
1031 3 : if(type == le_xmlrpc_server) {
1032 : /* HACK: use output encoding for now */
1033 3 : input_opts.xml_elem_opts.encoding = utf8_get_encoding_id_from_string(out.xmlrpc_out.xml_elem_opts.encoding);
1034 :
1035 : /* generate an XMLRPC_REQUEST from the raw xml input */
1036 3 : xRequest = XMLRPC_REQUEST_FromXML(Z_STRVAL_PP(rawxml), Z_STRLEN_PP(rawxml), &input_opts);
1037 :
1038 3 : if(xRequest) {
1039 3 : const char* methodname = XMLRPC_RequestGetMethodName(xRequest);
1040 : zval **php_function;
1041 3 : XMLRPC_VALUE xAnswer = NULL;
1042 3 : MAKE_STD_ZVAL(data.xmlrpc_method); /* init. very important. spent a frustrating day finding this out. */
1043 3 : MAKE_STD_ZVAL(data.return_data);
1044 3 : Z_TYPE_P(data.return_data) = IS_NULL; /* in case value is never init'd, we don't dtor to think it is a string or something */
1045 3 : Z_TYPE_P(data.xmlrpc_method) = IS_NULL;
1046 :
1047 3 : if (!methodname) {
1048 0 : methodname = "";
1049 : }
1050 :
1051 : /* setup some data to pass to the callback function */
1052 3 : Z_STRVAL_P(data.xmlrpc_method) = estrdup(methodname);
1053 3 : Z_STRLEN_P(data.xmlrpc_method) = strlen(methodname);
1054 3 : Z_TYPE_P(data.xmlrpc_method) = IS_STRING;
1055 3 : data.caller_params = *caller_params;
1056 3 : data.php_executed = 0;
1057 3 : data.server = server;
1058 :
1059 : /* check if the called method has been previous registered */
1060 3 : if(zend_hash_find(Z_ARRVAL_P(server->method_map),
1061 : Z_STRVAL_P(data.xmlrpc_method),
1062 : Z_STRLEN_P(data.xmlrpc_method) + 1,
1063 : (void**)&php_function) == SUCCESS) {
1064 :
1065 1 : data.php_function = *php_function;
1066 : }
1067 :
1068 : /* We could just call the php method directly ourselves at this point, but we do this
1069 : * with a C callback in case the xmlrpc library ever implements some cool usage stats,
1070 : * or somesuch.
1071 : */
1072 3 : xAnswer = XMLRPC_ServerCallMethod(server->server_ptr, xRequest, &data);
1073 3 : if(xAnswer && out.b_php_out) {
1074 0 : zval_dtor(data.return_data);
1075 0 : FREE_ZVAL(data.return_data);
1076 0 : data.return_data = XMLRPC_to_PHP(xAnswer);
1077 3 : } else if(data.php_executed && !out.b_php_out) {
1078 1 : xAnswer = PHP_to_XMLRPC(data.return_data TSRMLS_CC);
1079 : }
1080 :
1081 : /* should we return data as xml? */
1082 3 : if(!out.b_php_out) {
1083 3 : XMLRPC_REQUEST xResponse = XMLRPC_RequestNew();
1084 3 : if(xResponse) {
1085 3 : char *outBuf = 0;
1086 3 : int buf_len = 0;
1087 :
1088 : /* automagically determine output serialization type from request type */
1089 3 : if (out.b_auto_version) {
1090 1 : XMLRPC_REQUEST_OUTPUT_OPTIONS opts = XMLRPC_RequestGetOutputOptions(xRequest);
1091 1 : if (opts) {
1092 1 : out.xmlrpc_out.version = opts->version;
1093 : }
1094 : }
1095 : /* set some required request hoojum */
1096 3 : XMLRPC_RequestSetOutputOptions(xResponse, &out.xmlrpc_out);
1097 3 : XMLRPC_RequestSetRequestType(xResponse, xmlrpc_request_response);
1098 3 : XM |