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