root/ext/xmlrpc/xmlrpc-epi-php.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ZEND_GET_MODULE
  2. destroy_server_data
  3. xmlrpc_server_destructor
  4. PHP_MINIT_FUNCTION
  5. PHP_MINFO_FUNCTION
  6. add_long
  7. add_double
  8. add_string
  9. add_stringl
  10. add_zval
  11. set_output_options
  12. determine_vector_type
  13. PHP_to_XMLRPC_worker
  14. PHP_to_XMLRPC
  15. XMLRPC_to_PHP
  16. PHP_FUNCTION
  17. PHP_FUNCTION
  18. decode_request_worker
  19. PHP_FUNCTION
  20. PHP_FUNCTION
  21. PHP_FUNCTION
  22. PHP_FUNCTION
  23. php_xmlrpc_callback
  24. php_xmlrpc_introspection_callback
  25. PHP_FUNCTION
  26. PHP_FUNCTION
  27. PHP_FUNCTION
  28. PHP_FUNCTION
  29. PHP_FUNCTION
  30. get_type_str_mapping
  31. xmlrpc_type_as_str
  32. xmlrpc_str_as_type
  33. xmlrpc_str_as_vector_type
  34. set_zval_xmlrpc_type
  35. get_zval_xmlrpc_type
  36. PHP_FUNCTION
  37. PHP_FUNCTION
  38. PHP_FUNCTION

   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-2016 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$ */
  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 "ext/standard/php_string.h"
  71 #include "ext/date/php_date.h"
  72 #include "php_ini.h"
  73 #include "php_xmlrpc.h"
  74 #include "xmlrpc.h"
  75 
  76 #define PHP_EXT_VERSION "0.51"
  77 
  78 static int le_xmlrpc_server;
  79 
  80 /* {{{ arginfo */
  81 ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_encode, 0, 0, 1)
  82         ZEND_ARG_INFO(0, value)
  83 ZEND_END_ARG_INFO()
  84 
  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 ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_decode_request, 0, 0, 2)
  91         ZEND_ARG_INFO(0, xml)
  92         ZEND_ARG_INFO(1, method)
  93         ZEND_ARG_INFO(0, encoding)
  94 ZEND_END_ARG_INFO()
  95 
  96 ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_encode_request, 0, 0, 2)
  97         ZEND_ARG_INFO(0, method)
  98         ZEND_ARG_INFO(0, params)
  99         ZEND_ARG_INFO(0, output_options)
 100 ZEND_END_ARG_INFO()
 101 
 102 ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_set_type, 0, 0, 2)
 103         ZEND_ARG_INFO(1, value)
 104         ZEND_ARG_INFO(0, type)
 105 ZEND_END_ARG_INFO()
 106 
 107 ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_is_fault, 0, 0, 1)
 108         ZEND_ARG_INFO(0, arg)
 109 ZEND_END_ARG_INFO()
 110 
 111 ZEND_BEGIN_ARG_INFO(arginfo_xmlrpc_server_create, 0)
 112 ZEND_END_ARG_INFO()
 113 
 114 ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_server_destroy, 0, 0, 1)
 115         ZEND_ARG_INFO(0, server)
 116 ZEND_END_ARG_INFO()
 117 
 118 ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_server_register_method, 0, 0, 3)
 119         ZEND_ARG_INFO(0, server)
 120         ZEND_ARG_INFO(0, method_name)
 121         ZEND_ARG_INFO(0, function)
 122 ZEND_END_ARG_INFO()
 123 
 124 ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_server_call_method, 0, 0, 3)
 125         ZEND_ARG_INFO(0, server)
 126         ZEND_ARG_INFO(0, xml)
 127         ZEND_ARG_INFO(0, user_data)
 128         ZEND_ARG_INFO(0, output_options)
 129 ZEND_END_ARG_INFO()
 130 
 131 ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_parse_method_descriptions, 0, 0, 1)
 132         ZEND_ARG_INFO(0, xml)
 133 ZEND_END_ARG_INFO()
 134 
 135 ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_server_add_introspection_data, 0, 0, 2)
 136         ZEND_ARG_INFO(0, server)
 137         ZEND_ARG_INFO(0, desc)
 138 ZEND_END_ARG_INFO()
 139 
 140 ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_server_register_introspection_callback, 0, 0, 2)
 141         ZEND_ARG_INFO(0, server)
 142         ZEND_ARG_INFO(0, function)
 143 ZEND_END_ARG_INFO()
 144 /* }}} */
 145 
 146 const zend_function_entry xmlrpc_functions[] = {
 147         PHP_FE(xmlrpc_encode,                                                                   arginfo_xmlrpc_encode) 
 148         PHP_FE(xmlrpc_decode,                                                                   arginfo_xmlrpc_decode)
 149         PHP_FE(xmlrpc_decode_request,                                                   arginfo_xmlrpc_decode_request)
 150         PHP_FE(xmlrpc_encode_request,                                                   arginfo_xmlrpc_encode_request)
 151         PHP_FE(xmlrpc_get_type,                                                                 arginfo_xmlrpc_encode)
 152         PHP_FE(xmlrpc_set_type,                                                                 arginfo_xmlrpc_set_type)
 153         PHP_FE(xmlrpc_is_fault,                                                                 arginfo_xmlrpc_is_fault)
 154         PHP_FE(xmlrpc_server_create,                                                    arginfo_xmlrpc_server_create)
 155         PHP_FE(xmlrpc_server_destroy,                                                   arginfo_xmlrpc_server_destroy)
 156         PHP_FE(xmlrpc_server_register_method,                                   arginfo_xmlrpc_server_register_method)
 157         PHP_FE(xmlrpc_server_call_method,                                               arginfo_xmlrpc_server_call_method)
 158         PHP_FE(xmlrpc_parse_method_descriptions,                                arginfo_xmlrpc_parse_method_descriptions)
 159         PHP_FE(xmlrpc_server_add_introspection_data,                    arginfo_xmlrpc_server_add_introspection_data)
 160         PHP_FE(xmlrpc_server_register_introspection_callback,   arginfo_xmlrpc_server_register_introspection_callback)
 161         PHP_FE_END
 162 };
 163 
 164 zend_module_entry xmlrpc_module_entry = {
 165         STANDARD_MODULE_HEADER,
 166         "xmlrpc",
 167         xmlrpc_functions,
 168         PHP_MINIT(xmlrpc),
 169         NULL,
 170         NULL,
 171         NULL,
 172         PHP_MINFO(xmlrpc),
 173         PHP_EXT_VERSION,
 174         STANDARD_MODULE_PROPERTIES
 175 };
 176 
 177 #ifdef COMPILE_DL_XMLRPC
 178 ZEND_GET_MODULE(xmlrpc)
 179 #endif
 180 
 181 /*******************************
 182 * local structures and defines *
 183 *******************************/
 184 
 185 /* per server data */
 186 typedef struct _xmlrpc_server_data {
 187         zval* method_map;
 188         zval* introspection_map;
 189         XMLRPC_SERVER server_ptr;
 190 } xmlrpc_server_data;
 191 
 192 
 193 /* how to format output */
 194 typedef struct _php_output_options {
 195         int b_php_out;
 196         int b_auto_version;
 197         STRUCT_XMLRPC_REQUEST_OUTPUT_OPTIONS xmlrpc_out;
 198 } php_output_options;
 199 
 200 /* data passed to C callback */
 201 typedef struct _xmlrpc_callback_data {
 202         zval* xmlrpc_method;
 203         zval* php_function;
 204         zval* caller_params;
 205         zval* return_data;
 206         xmlrpc_server_data* server;
 207         char php_executed;
 208 } xmlrpc_callback_data;
 209 
 210 /* output options */
 211 #define OUTPUT_TYPE_KEY       "output_type"
 212 #define OUTPUT_TYPE_KEY_LEN   (sizeof(OUTPUT_TYPE_KEY) - 1)
 213 #define OUTPUT_TYPE_VALUE_PHP "php"
 214 #define OUTPUT_TYPE_VALUE_XML "xml"
 215 
 216 #define VERBOSITY_KEY                  "verbosity"
 217 #define VERBOSITY_KEY_LEN              (sizeof(VERBOSITY_KEY) - 1)
 218 #define VERBOSITY_VALUE_NO_WHITE_SPACE "no_white_space"
 219 #define VERBOSITY_VALUE_NEWLINES_ONLY  "newlines_only"
 220 #define VERBOSITY_VALUE_PRETTY         "pretty"
 221 
 222 #define ESCAPING_KEY             "escaping"
 223 #define ESCAPING_KEY_LEN         (sizeof(ESCAPING_KEY) - 1)
 224 #define ESCAPING_VALUE_CDATA     "cdata"
 225 #define ESCAPING_VALUE_NON_ASCII "non-ascii"
 226 #define ESCAPING_VALUE_NON_PRINT "non-print"
 227 #define ESCAPING_VALUE_MARKUP    "markup"
 228 
 229 #define VERSION_KEY          "version"
 230 #define VERSION_KEY_LEN      (sizeof(VERSION_KEY) - 1)
 231 #define VERSION_VALUE_SIMPLE "simple"
 232 #define VERSION_VALUE_XMLRPC "xmlrpc"
 233 #define VERSION_VALUE_SOAP11 "soap 1.1"
 234 #define VERSION_VALUE_AUTO   "auto"
 235 
 236 #define ENCODING_KEY     "encoding"
 237 #define ENCODING_KEY_LEN (sizeof(ENCODING_KEY) - 1)
 238 #define ENCODING_DEFAULT "iso-8859-1"
 239 
 240 /* value types */
 241 #define OBJECT_TYPE_ATTR  "xmlrpc_type"
 242 #define OBJECT_VALUE_ATTR "scalar"
 243 #define OBJECT_VALUE_TS_ATTR "timestamp"
 244 
 245 /* faults */
 246 #define FAULT_CODE       "faultCode"
 247 #define FAULT_CODE_LEN   (sizeof(FAULT_CODE) - 1)
 248 #define FAULT_STRING     "faultString"
 249 #define FAULT_STRING_LEN (sizeof(FAULT_STRING) - 1)
 250 
 251 /***********************
 252 * forward declarations *
 253 ***********************/
 254 XMLRPC_VALUE_TYPE get_zval_xmlrpc_type(zval* value, zval** newvalue);
 255 static void php_xmlrpc_introspection_callback(XMLRPC_SERVER server, void* data);
 256 int sset_zval_xmlrpc_type(zval* value, XMLRPC_VALUE_TYPE type);
 257 zval* decode_request_worker(char *xml_in, int xml_in_len, char *encoding_in, zval* method_name_out);
 258 const char* xmlrpc_type_as_str(XMLRPC_VALUE_TYPE type, XMLRPC_VECTOR_TYPE vtype);
 259 XMLRPC_VALUE_TYPE xmlrpc_str_as_type(const char* str);
 260 XMLRPC_VECTOR_TYPE xmlrpc_str_as_vector_type(const char* str);
 261 int set_zval_xmlrpc_type(zval* value, XMLRPC_VALUE_TYPE type);
 262 
 263 /*********************
 264 * startup / shutdown *
 265 *********************/
 266 
 267 static void destroy_server_data(xmlrpc_server_data *server TSRMLS_DC)
 268 {
 269         if (server) {
 270                 XMLRPC_ServerDestroy(server->server_ptr);
 271 
 272                 zval_dtor(server->method_map);
 273                 FREE_ZVAL(server->method_map);
 274 
 275                 zval_dtor(server->introspection_map);
 276                 FREE_ZVAL(server->introspection_map);
 277 
 278                 efree(server);
 279         }
 280 }
 281 
 282 /* called when server is being destructed. either when xmlrpc_server_destroy
 283  * is called, or when request ends.  */
 284 static void xmlrpc_server_destructor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
 285 {
 286         if (rsrc && rsrc->ptr) {
 287                 destroy_server_data((xmlrpc_server_data*) rsrc->ptr TSRMLS_CC);
 288         }
 289 }
 290 
 291 /* module init */
 292 PHP_MINIT_FUNCTION(xmlrpc)
 293 {
 294         le_xmlrpc_server = zend_register_list_destructors_ex(xmlrpc_server_destructor, NULL, "xmlrpc server", module_number);
 295 
 296         return SUCCESS;
 297 }
 298 
 299 /* display info in phpinfo() */
 300 PHP_MINFO_FUNCTION(xmlrpc)
 301 {
 302         php_info_print_table_start();
 303         php_info_print_table_row(2, "core library version", XMLRPC_GetVersionString());
 304         php_info_print_table_row(2, "php extension version", PHP_EXT_VERSION);
 305         php_info_print_table_row(2, "author", "Dan Libby");
 306         php_info_print_table_row(2, "homepage", "http://xmlrpc-epi.sourceforge.net");
 307         php_info_print_table_row(2, "open sourced by", "Epinions.com");
 308         php_info_print_table_end();
 309 }
 310 
 311 /*******************
 312 * random utilities *
 313 *******************/
 314 
 315 /* Utility functions for adding data types to arrays, with or without key (assoc, non-assoc).
 316  * Could easily be further generalized to work with objects.
 317  */
 318 #if 0
 319 static int add_long(zval* list, char* id, int num) {
 320         if(id) return add_assoc_long(list, id, num);
 321         else   return add_next_index_long(list, num);
 322 }
 323 
 324 static int add_double(zval* list, char* id, double num) {
 325         if(id) return add_assoc_double(list, id, num);
 326         else   return add_next_index_double(list, num);
 327 }
 328 
 329 static int add_string(zval* list, char* id, char* string, int duplicate) {
 330         if(id) return add_assoc_string(list, id, string, duplicate);
 331         else   return add_next_index_string(list, string, duplicate);
 332 }
 333 
 334 static int add_stringl(zval* list, char* id, char* string, uint length, int duplicate) {
 335         if(id) return add_assoc_stringl(list, id, string, length, duplicate);
 336         else   return add_next_index_stringl(list, string, length, duplicate);
 337 }
 338 
 339 #endif
 340 
 341 static int add_zval(zval* list, const char* id, zval** val)
 342 {
 343         if (list && val) {
 344                 if (id) {
 345                         int id_len = strlen(id);
 346                         if (!(id_len > 1 && id[0] == '0') && is_numeric_string((char *)id, id_len, NULL, NULL, 0) == IS_LONG) {
 347                                 long index = strtol(id, NULL, 0);
 348                                 return zend_hash_index_update(Z_ARRVAL_P(list), index, (void *) val, sizeof(zval **), NULL);
 349                         } else {
 350                                 return zend_hash_update(Z_ARRVAL_P(list), (char*) id, strlen(id) + 1, (void *) val, sizeof(zval **), NULL);
 351                         }
 352                 } else {
 353                         return zend_hash_next_index_insert(Z_ARRVAL_P(list), (void *) val, sizeof(zval **), NULL); 
 354                 }
 355         }
 356         /* what is the correct return on error? */
 357         return 0;
 358 }
 359 
 360 #define my_zend_hash_get_current_key(ht, my_key, num_index) zend_hash_get_current_key(ht, my_key, num_index, 0)
 361 
 362 
 363 /*************************
 364 * input / output options *
 365 *************************/
 366 
 367 /* parse an array (user input) into output options suitable for use by xmlrpc engine
 368  * and determine whether to return data as xml or php vars */
 369 static void set_output_options(php_output_options* options, zval* output_opts)
 370 {
 371         if (options) {
 372 
 373                 /* defaults */
 374                 options->b_php_out = 0;
 375                 options->b_auto_version = 1;
 376                 options->xmlrpc_out.version = xmlrpc_version_1_0;
 377                 options->xmlrpc_out.xml_elem_opts.encoding = ENCODING_DEFAULT;
 378                 options->xmlrpc_out.xml_elem_opts.verbosity = xml_elem_pretty;
 379                 options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_markup_escaping | xml_elem_non_ascii_escaping | xml_elem_non_print_escaping;
 380 
 381                 if (output_opts && Z_TYPE_P(output_opts) == IS_ARRAY) {
 382                         zval** val;
 383 
 384                         /* type of output (xml/php) */
 385                         if (zend_hash_find(Z_ARRVAL_P(output_opts), OUTPUT_TYPE_KEY, OUTPUT_TYPE_KEY_LEN + 1, (void**) &val) == SUCCESS) {
 386                                 if (Z_TYPE_PP(val) == IS_STRING) {
 387                                         if (!strcmp(Z_STRVAL_PP(val), OUTPUT_TYPE_VALUE_PHP)) {
 388                                                 options->b_php_out = 1;
 389                                         } else if (!strcmp(Z_STRVAL_PP(val), OUTPUT_TYPE_VALUE_XML)) {
 390                                                 options->b_php_out = 0;
 391                                         }
 392                                 }
 393                         }
 394 
 395                         /* verbosity of generated xml */
 396                         if (zend_hash_find(Z_ARRVAL_P(output_opts), VERBOSITY_KEY, VERBOSITY_KEY_LEN + 1, (void**) &val) == SUCCESS) {
 397                                 if (Z_TYPE_PP(val) == IS_STRING) {
 398                                         if (!strcmp(Z_STRVAL_PP(val), VERBOSITY_VALUE_NO_WHITE_SPACE)) {
 399                                                 options->xmlrpc_out.xml_elem_opts.verbosity = xml_elem_no_white_space;
 400                                         } else if (!strcmp(Z_STRVAL_PP(val), VERBOSITY_VALUE_NEWLINES_ONLY)) {
 401                                                 options->xmlrpc_out.xml_elem_opts.verbosity = xml_elem_newlines_only;
 402                                         } else if (!strcmp(Z_STRVAL_PP(val), VERBOSITY_VALUE_PRETTY)) {
 403                                                 options->xmlrpc_out.xml_elem_opts.verbosity = xml_elem_pretty;
 404                                         }
 405                                 }
 406                         }
 407 
 408                         /* version of xml to output */
 409                         if (zend_hash_find(Z_ARRVAL_P(output_opts), VERSION_KEY, VERSION_KEY_LEN + 1, (void**) &val) == SUCCESS) {
 410                                 if (Z_TYPE_PP(val) == IS_STRING) {
 411                                         options->b_auto_version = 0;
 412                                         if (!strcmp(Z_STRVAL_PP(val), VERSION_VALUE_XMLRPC)) {
 413                                                 options->xmlrpc_out.version = xmlrpc_version_1_0;
 414                                         } else if (!strcmp(Z_STRVAL_PP(val), VERSION_VALUE_SIMPLE)) {
 415                                                 options->xmlrpc_out.version = xmlrpc_version_simple;
 416                                         } else if (!strcmp((*val)->value.str.val, VERSION_VALUE_SOAP11)) {
 417                                                         options->xmlrpc_out.version = xmlrpc_version_soap_1_1;
 418                                         } else { /* if(!strcmp((*val)->value.str.val, VERSION_VALUE_AUTO)) { */
 419                                                         options->b_auto_version = 1;
 420                                         }
 421                                 }
 422                         }
 423 
 424                         /* encoding code set */
 425                         if (zend_hash_find(Z_ARRVAL_P(output_opts), ENCODING_KEY, ENCODING_KEY_LEN + 1, (void**)&val) == SUCCESS) {
 426                                 if (Z_TYPE_PP(val) == IS_STRING) {
 427                                         options->xmlrpc_out.xml_elem_opts.encoding = estrdup(Z_STRVAL_PP(val));
 428                                 }
 429                         }
 430 
 431                         /* escaping options */
 432                         if (zend_hash_find(Z_ARRVAL_P(output_opts), ESCAPING_KEY, ESCAPING_KEY_LEN + 1, (void**)&val) == SUCCESS) {
 433                                 /* multiple values allowed.  check if array */
 434                                 if (Z_TYPE_PP(val) == IS_ARRAY) {
 435                                         zval** iter_val;
 436 
 437                                         zend_hash_internal_pointer_reset(Z_ARRVAL_PP(val));
 438                                         options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_no_escaping;
 439 
 440                                         while (1) {
 441                                                 if (zend_hash_get_current_data(Z_ARRVAL_PP(val), (void**)&iter_val) == SUCCESS) {
 442                                                         if (Z_TYPE_PP(iter_val) == IS_STRING && Z_STRVAL_PP(iter_val)) {
 443                                                                 if (!strcmp(Z_STRVAL_PP(iter_val), ESCAPING_VALUE_CDATA)) {
 444                                                                         options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_cdata_escaping;
 445                                                                 } else if (!strcmp(Z_STRVAL_PP(iter_val), ESCAPING_VALUE_NON_ASCII)) {
 446                                                                         options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_non_ascii_escaping;
 447                                                                 } else if (!strcmp(Z_STRVAL_PP(iter_val), ESCAPING_VALUE_NON_PRINT)) {
 448                                                                         options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_non_print_escaping;
 449                                                                 } else if (!strcmp(Z_STRVAL_PP(iter_val), ESCAPING_VALUE_MARKUP)) {
 450                                                                         options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_markup_escaping;
 451                                                                 }
 452                                                         }
 453                                                 } else {
 454                                                         break;
 455                                                 }
 456                                                 zend_hash_move_forward(Z_ARRVAL_PP(val));
 457                                         }
 458                                 /* else, check for single value */
 459                                 } else if (Z_TYPE_PP(val) == IS_STRING) {
 460                                         if (!strcmp(Z_STRVAL_PP(val), ESCAPING_VALUE_CDATA)) {
 461                                                 options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_cdata_escaping;
 462                                         } else if (!strcmp(Z_STRVAL_PP(val), ESCAPING_VALUE_NON_ASCII)) {
 463                                                 options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_non_ascii_escaping;
 464                                         } else if (!strcmp(Z_STRVAL_PP(val), ESCAPING_VALUE_NON_PRINT)) {
 465                                                 options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_non_print_escaping;
 466                                         } else if (!strcmp(Z_STRVAL_PP(val), ESCAPING_VALUE_MARKUP)) {
 467                                                 options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_markup_escaping;
 468                                         }
 469                                 }
 470                         }
 471                 }
 472         }
 473 }
 474 
 475 
 476 /******************
 477 * encode / decode *
 478 ******************/
 479 
 480 /* php arrays have no distinction between array and struct types.
 481  * they even allow mixed.  Thus, we determine the type by iterating
 482  * through the entire array and figuring out each element.
 483  * room for some optimation here if we stop after a specific # of elements.
 484  */
 485 static XMLRPC_VECTOR_TYPE determine_vector_type (HashTable *ht)
 486 {
 487         int bArray = 0, bStruct = 0, bMixed = 0;
 488         unsigned long num_index, last_num = 0;
 489         char* my_key;
 490 
 491         zend_hash_internal_pointer_reset(ht);
 492         while (1) {
 493                 int res = my_zend_hash_get_current_key(ht, &my_key, &num_index);
 494                 
 495                 if (res == HASH_KEY_IS_LONG) {
 496                         if (bStruct) {
 497                                 bMixed = 1;
 498                                 break;
 499                         } else if (last_num > 0 && last_num != num_index-1) {
 500                                 bStruct = 1;
 501                                 break;
 502                         }
 503                         bArray = 1;
 504                         last_num = num_index;
 505                 } else if (res == HASH_KEY_NON_EXISTENT) {
 506                         break;
 507                 } else if (res == HASH_KEY_IS_STRING) {
 508                         if (bArray) {
 509                                 bMixed = 1;
 510                                 break;
 511                         }
 512                         bStruct = 1;
 513                 }
 514                 zend_hash_move_forward(ht);
 515         }
 516         return bMixed ? xmlrpc_vector_mixed : (bStruct ? xmlrpc_vector_struct : xmlrpc_vector_array);
 517 }
 518 
 519 /* recursively convert php values into xmlrpc values */
 520 static XMLRPC_VALUE PHP_to_XMLRPC_worker (const char* key, zval* in_val, int depth TSRMLS_DC)
 521 {
 522         XMLRPC_VALUE xReturn = NULL;
 523 
 524         if (in_val) {
 525                 zval* val = NULL;
 526                 XMLRPC_VALUE_TYPE type = get_zval_xmlrpc_type(in_val, &val);
 527         
 528                 if (val) {
 529                         switch (type) {
 530                                 case xmlrpc_base64:
 531                                         if (Z_TYPE_P(val) == IS_NULL) {
 532                                                 xReturn = XMLRPC_CreateValueEmpty();
 533                                                 XMLRPC_SetValueID(xReturn, key, 0);
 534                                         } else {
 535                                                 if (Z_TYPE_P(val) != IS_STRING) {
 536                                                         zval *newvalue;
 537                                                         ALLOC_INIT_ZVAL(newvalue);
 538                                                         MAKE_COPY_ZVAL(&val, newvalue);
 539                                                         convert_to_string(newvalue);
 540                                                         xReturn = XMLRPC_CreateValueBase64(key, Z_STRVAL_P(newvalue), Z_STRLEN_P(newvalue));
 541                                                         zval_ptr_dtor(&newvalue);
 542                                                 } else {
 543                                                         xReturn = XMLRPC_CreateValueBase64(key, Z_STRVAL_P(val), Z_STRLEN_P(val));
 544                                                 }
 545                                         }
 546                                         break;
 547                                 case xmlrpc_datetime:
 548                                         convert_to_string(val);
 549                                         xReturn = XMLRPC_CreateValueDateTime_ISO8601(key, Z_STRVAL_P(val));
 550                                         break;
 551                                 case xmlrpc_boolean:
 552                                         convert_to_boolean(val);
 553                                         xReturn = XMLRPC_CreateValueBoolean(key, Z_LVAL_P(val));
 554                                         break;
 555                                 case xmlrpc_int:
 556                                         convert_to_long(val);
 557                                         xReturn = XMLRPC_CreateValueInt(key, Z_LVAL_P(val));
 558                                         break;
 559                                 case xmlrpc_double:
 560                                         convert_to_double(val);
 561                                         xReturn = XMLRPC_CreateValueDouble(key, Z_DVAL_P(val));
 562                                         break;
 563                                 case xmlrpc_string:
 564                                         convert_to_string(val);
 565                                         xReturn = XMLRPC_CreateValueString(key, Z_STRVAL_P(val), Z_STRLEN_P(val));
 566                                         break;
 567                                 case xmlrpc_vector:
 568                                         {
 569                                                 unsigned long num_index;
 570                                                 zval** pIter;
 571                                                 char* my_key;
 572                                                 HashTable *ht = NULL;
 573                                                 zval *val_arr;
 574                                                 XMLRPC_VECTOR_TYPE vtype;
 575 
 576                                                 ht = HASH_OF(val);
 577                                                 if (ht && ht->nApplyCount > 1) {
 578                                                         php_error_docref(NULL TSRMLS_CC, E_ERROR, "XML-RPC doesn't support circular references");
 579                                                         return NULL;
 580                                                 }
 581 
 582                                                 MAKE_STD_ZVAL(val_arr);
 583                                                 MAKE_COPY_ZVAL(&val, val_arr);
 584                                                 convert_to_array(val_arr);
 585                                                 
 586                                                 vtype = determine_vector_type(Z_ARRVAL_P(val_arr));
 587                                                 xReturn = XMLRPC_CreateVector(key, vtype);
 588 
 589                                                 zend_hash_internal_pointer_reset(Z_ARRVAL_P(val_arr));
 590                                                 while(zend_hash_get_current_data(Z_ARRVAL_P(val_arr), (void**)&pIter) == SUCCESS) {
 591                                                         int res = my_zend_hash_get_current_key(Z_ARRVAL_P(val_arr), &my_key, &num_index);
 592 
 593                                                         switch (res) {
 594                                                                 case HASH_KEY_NON_EXISTENT:
 595                                                                         break;
 596                                                                 case HASH_KEY_IS_STRING:
 597                                                                 case HASH_KEY_IS_LONG:
 598                                                                         ht = HASH_OF(*pIter);
 599                                                                         if (ht) {
 600                                                                                 ht->nApplyCount++;
 601                                                                         }
 602                                                                         if (res == HASH_KEY_IS_LONG) {
 603                                                                                 char *num_str = NULL;
 604                                                                                 
 605                                                                                 if (vtype != xmlrpc_vector_array) {
 606                                                                                         spprintf(&num_str, 0, "%ld", num_index);
 607                                                                                 }
 608                                                                                 XMLRPC_AddValueToVector(xReturn, PHP_to_XMLRPC_worker(num_str, *pIter, depth++ TSRMLS_CC));
 609                                                                                 if (num_str) {
 610                                                                                         efree(num_str);
 611                                                                                 }
 612                                                                         } else {
 613                                                                                 XMLRPC_AddValueToVector(xReturn, PHP_to_XMLRPC_worker(my_key, *pIter, depth++ TSRMLS_CC));
 614                                                                         }
 615                                                                         if (ht) {
 616                                                                                 ht->nApplyCount--;
 617                                                                         }
 618                                                                         break;
 619                                                         }
 620                                                         zend_hash_move_forward(Z_ARRVAL_P(val_arr));
 621                                                 }       
 622                                                 zval_ptr_dtor(&val_arr);
 623                                         }
 624                                         break;
 625                                 default:
 626                                         break;
 627                         }
 628                 }
 629         }
 630         return xReturn;
 631 }
 632 
 633 static XMLRPC_VALUE PHP_to_XMLRPC(zval* root_val TSRMLS_DC)
 634 {
 635         return PHP_to_XMLRPC_worker(NULL, root_val, 0 TSRMLS_CC);
 636 }
 637 
 638 /* recursively convert xmlrpc values into php values */
 639 static zval* XMLRPC_to_PHP(XMLRPC_VALUE el)
 640 {
 641         zval* elem = NULL;
 642         const char* pStr;
 643 
 644         if (el) {
 645                 XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(el);
 646 
 647                 MAKE_STD_ZVAL(elem); /* init. very important.  spent a frustrating day finding this out. */
 648 
 649                 switch(type) {
 650                         case xmlrpc_empty:
 651                                 Z_TYPE_P(elem) = IS_NULL;
 652                                 break;
 653                         case xmlrpc_string:
 654                                 pStr = XMLRPC_GetValueString(el);
 655                                 if (pStr) {
 656                                         Z_STRLEN_P(elem) = XMLRPC_GetValueStringLen(el);
 657                                         Z_STRVAL_P(elem) = estrndup(pStr, Z_STRLEN_P(elem));
 658                                         Z_TYPE_P(elem) = IS_STRING;
 659                                 }
 660                                 break;
 661                         case xmlrpc_int:
 662                                 Z_LVAL_P(elem) = XMLRPC_GetValueInt(el);
 663                                 Z_TYPE_P(elem) = IS_LONG;
 664                                 break;
 665                         case xmlrpc_boolean:
 666                                 Z_LVAL_P(elem) = XMLRPC_GetValueBoolean(el);
 667                                 Z_TYPE_P(elem) = IS_BOOL;
 668                                 break;
 669                         case xmlrpc_double:
 670                                 Z_DVAL_P(elem) = XMLRPC_GetValueDouble(el);
 671                                 Z_TYPE_P(elem) = IS_DOUBLE;
 672                                 break;
 673                         case xmlrpc_datetime:
 674                                 Z_STRLEN_P(elem) = XMLRPC_GetValueStringLen(el);
 675                                 Z_STRVAL_P(elem) = estrndup(XMLRPC_GetValueDateTime_ISO8601(el), Z_STRLEN_P(elem));
 676                                 Z_TYPE_P(elem) = IS_STRING;
 677                                 break;
 678                         case xmlrpc_base64:
 679                                 pStr = XMLRPC_GetValueBase64(el);
 680                                 if (pStr) {
 681                                         Z_STRLEN_P(elem) = XMLRPC_GetValueStringLen(el);
 682                                         Z_STRVAL_P(elem) = estrndup(pStr, Z_STRLEN_P(elem));
 683                                         Z_TYPE_P(elem) = IS_STRING;
 684                                 }
 685                                 break;
 686                         case xmlrpc_vector:
 687                                 array_init(elem);
 688                                 {
 689                                         XMLRPC_VALUE xIter = XMLRPC_VectorRewind(el);
 690 
 691                                         while( xIter ) {
 692                                                 zval *val = XMLRPC_to_PHP(xIter);
 693                                                 if (val) {
 694                                                         add_zval(elem, XMLRPC_GetValueID(xIter), &val);
 695                                                 }
 696                                                 xIter = XMLRPC_VectorNext(el);
 697                                         }
 698                                 }
 699                                 break;
 700                         default:
 701                                 break;
 702                 }
 703                 set_zval_xmlrpc_type(elem, type);
 704         }
 705         return elem;
 706 }
 707 
 708 /* {{{ proto string xmlrpc_encode_request(string method, mixed params [, array output_options])
 709    Generates XML for a method request */
 710 PHP_FUNCTION(xmlrpc_encode_request)
 711 {
 712         XMLRPC_REQUEST xRequest = NULL;
 713         char *outBuf;
 714         zval *vals, *out_opts = NULL;
 715         char *method = NULL;
 716         int method_len;
 717         php_output_options out;
 718 
 719         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!z|a", &method, &method_len, &vals, &out_opts) == FAILURE) {
 720                 return;
 721         }
 722 
 723         set_output_options(&out, out_opts ? out_opts : 0);
 724 
 725         if (return_value_used) {
 726                 xRequest = XMLRPC_RequestNew();
 727 
 728                 if (xRequest) {
 729                         XMLRPC_RequestSetOutputOptions(xRequest, &out.xmlrpc_out);
 730                         if (method == NULL) {
 731                                 XMLRPC_RequestSetRequestType(xRequest, xmlrpc_request_response);
 732                         } else {
 733                                 XMLRPC_RequestSetMethodName(xRequest, method);
 734                                 XMLRPC_RequestSetRequestType(xRequest, xmlrpc_request_call);
 735                         }
 736                         if (Z_TYPE_P(vals) != IS_NULL) {
 737                                 XMLRPC_RequestSetData(xRequest, PHP_to_XMLRPC(vals TSRMLS_CC));
 738                         }
 739 
 740                         outBuf = XMLRPC_REQUEST_ToXML(xRequest, 0);
 741                         if (outBuf) {
 742                                 RETVAL_STRING(outBuf, 1);
 743                                 free(outBuf);
 744                         }
 745                         XMLRPC_RequestFree(xRequest, 1);
 746                 }
 747         }
 748         
 749         if (strcmp(out.xmlrpc_out.xml_elem_opts.encoding, ENCODING_DEFAULT) != 0) {
 750                 efree((char *)out.xmlrpc_out.xml_elem_opts.encoding);
 751         }
 752 }
 753 /* }}} */
 754 
 755 /* {{{ proto string xmlrpc_encode(mixed value)
 756    Generates XML for a PHP value */
 757 PHP_FUNCTION(xmlrpc_encode)
 758 {
 759         XMLRPC_VALUE xOut = NULL;
 760         zval **arg1;
 761         char *outBuf;
 762 
 763         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg1) == FAILURE) {
 764                 return;
 765         }
 766 
 767         if (return_value_used) {
 768                 /* convert native php type to xmlrpc type */
 769                 xOut = PHP_to_XMLRPC(*arg1 TSRMLS_CC);
 770 
 771                 /* generate raw xml from xmlrpc data */
 772                 outBuf = XMLRPC_VALUE_ToXML(xOut, 0);
 773 
 774                 if (xOut) {
 775                         if (outBuf) {
 776                                 RETVAL_STRING(outBuf, 1);
 777                                 free(outBuf);
 778                         }
 779                         /* cleanup */
 780                         XMLRPC_CleanupValue(xOut);
 781                 }
 782         }
 783 }
 784 /* }}} */
 785 
 786 zval* decode_request_worker(char *xml_in, int xml_in_len, char *encoding_in, zval* method_name_out) /* {{{ */
 787 {
 788         zval* retval = NULL;
 789         XMLRPC_REQUEST response;
 790         STRUCT_XMLRPC_REQUEST_INPUT_OPTIONS opts = {{0}};
 791         const char *method_name;
 792         opts.xml_elem_opts.encoding = encoding_in ? utf8_get_encoding_id_from_string(encoding_in) : ENCODING_DEFAULT;
 793 
 794         /* generate XMLRPC_REQUEST from raw xml */
 795         response = XMLRPC_REQUEST_FromXML(xml_in, xml_in_len, &opts);
 796         if (response) {
 797                 /* convert xmlrpc data to native php types */
 798                 retval = XMLRPC_to_PHP(XMLRPC_RequestGetData(response));
 799 
 800                 if (XMLRPC_RequestGetRequestType(response) == xmlrpc_request_call) {
 801                         if (method_name_out) {
 802                                 method_name = XMLRPC_RequestGetMethodName(response);
 803                                 if (method_name) {
 804                                         zval_dtor(method_name_out);
 805                                         Z_TYPE_P(method_name_out) = IS_STRING;
 806                                         Z_STRVAL_P(method_name_out) = estrdup(method_name);
 807                                         Z_STRLEN_P(method_name_out) = strlen(Z_STRVAL_P(method_name_out));
 808                                 } else if (retval) {
 809                                         zval_ptr_dtor(&retval);
 810                                         retval = NULL;
 811                                 }
 812                         }
 813                 }
 814 
 815                 /* dust, sweep, and mop */
 816                 XMLRPC_RequestFree(response, 1);
 817         }
 818         return retval;
 819 }
 820 /* }}} */
 821 
 822 /* {{{ proto array xmlrpc_decode_request(string xml, string& method [, string encoding])
 823    Decodes XML into native PHP types */
 824 PHP_FUNCTION(xmlrpc_decode_request)
 825 {
 826         char *xml, *encoding = NULL;
 827         zval **method;
 828         int xml_len, encoding_len = 0;
 829 
 830         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sZ|s", &xml, &xml_len, &method, &encoding, &encoding_len) == FAILURE) {
 831                 return;
 832         }
 833 
 834 
 835         if (return_value_used) {
 836                 zval* retval = decode_request_worker(xml, xml_len, encoding_len ? encoding : NULL, *method);
 837                 if (retval) {
 838                         *return_value = *retval;
 839                         FREE_ZVAL(retval);
 840                 }
 841         }
 842 }
 843 /* }}} */
 844 
 845 /* {{{ proto array xmlrpc_decode(string xml [, string encoding])
 846    Decodes XML into native PHP types */
 847 PHP_FUNCTION(xmlrpc_decode)
 848 {
 849         char *arg1, *arg2 = NULL;
 850         int arg1_len, arg2_len = 0;
 851 
 852         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &arg1, &arg1_len, &arg2, &arg2_len) == FAILURE) {
 853                 return;
 854         }
 855 
 856         if (return_value_used) {
 857                 zval* retval = decode_request_worker(arg1, arg1_len, arg2_len ? arg2 : NULL, NULL);
 858                 if (retval) {
 859                         *return_value = *retval;
 860                         FREE_ZVAL(retval);
 861                 }
 862         }
 863 }
 864 /* }}} */
 865 
 866 /*************************
 867 * server related methods *
 868 *************************/
 869 
 870 /* {{{ proto resource xmlrpc_server_create(void)
 871    Creates an xmlrpc server */
 872 PHP_FUNCTION(xmlrpc_server_create)
 873 {
 874         if (zend_parse_parameters_none() == FAILURE) {
 875                 return;
 876         }
 877 
 878         if (return_value_used) {
 879                 zval *method_map, *introspection_map;
 880                 xmlrpc_server_data *server = emalloc(sizeof(xmlrpc_server_data));
 881                 MAKE_STD_ZVAL(method_map);
 882                 MAKE_STD_ZVAL(introspection_map);
 883                 
 884                 array_init(method_map);
 885                 array_init(introspection_map);
 886                 
 887                 /* allocate server data.  free'd in destroy_server_data() */
 888                 server->method_map = method_map;
 889                 server->introspection_map = introspection_map;
 890                 server->server_ptr = XMLRPC_ServerCreate();
 891 
 892                 XMLRPC_ServerRegisterIntrospectionCallback(server->server_ptr, php_xmlrpc_introspection_callback);
 893 
 894                 /* store for later use */
 895                 ZEND_REGISTER_RESOURCE(return_value,server, le_xmlrpc_server);
 896         }
 897 }
 898 /* }}} */
 899 
 900 /* {{{ proto int xmlrpc_server_destroy(resource server)
 901    Destroys server resources */
 902 PHP_FUNCTION(xmlrpc_server_destroy)
 903 {
 904         zval *arg1;
 905         int bSuccess = FAILURE, type;
 906         xmlrpc_server_data *server;
 907 
 908         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) {
 909                 return;
 910         }
 911 
 912         server = zend_list_find(Z_LVAL_P(arg1), &type);
 913 
 914         if (server && type == le_xmlrpc_server) {
 915                 bSuccess = zend_list_delete(Z_LVAL_P(arg1));
 916 
 917                 /* called by hashtable destructor
 918                  * destroy_server_data(server);
 919                  */
 920         }
 921         RETVAL_LONG(bSuccess == SUCCESS);
 922 }
 923 /* }}} */
 924            
 925 /* called by xmlrpc C engine as method handler for all registered methods.
 926  * it then calls the corresponding PHP function to handle the method.
 927  */
 928 static XMLRPC_VALUE php_xmlrpc_callback(XMLRPC_SERVER server, XMLRPC_REQUEST xRequest, void* data) /* {{{ */
 929 {
 930         xmlrpc_callback_data* pData = (xmlrpc_callback_data*)data;
 931         zval** php_function;
 932         zval* xmlrpc_params;
 933         zval* callback_params[3];
 934         TSRMLS_FETCH();
 935 
 936         zval_dtor(pData->xmlrpc_method);
 937         zval_dtor(pData->return_data);
 938 
 939         /* convert xmlrpc to native php types */
 940         ZVAL_STRING(pData->xmlrpc_method, XMLRPC_RequestGetMethodName(xRequest), 1);
 941         xmlrpc_params = XMLRPC_to_PHP(XMLRPC_RequestGetData(xRequest));
 942         
 943         /* check if the called method has been previous registered */
 944         if(zend_hash_find(Z_ARRVAL_P(pData->server->method_map),
 945                       Z_STRVAL_P(pData->xmlrpc_method), 
 946                       Z_STRLEN_P(pData->xmlrpc_method) + 1, 
 947                       (void**)&php_function) == SUCCESS) {
 948 
 949                 pData->php_function = *php_function;
 950         }
 951 
 952         /* setup data hoojum */
 953         callback_params[0] = pData->xmlrpc_method;
 954         callback_params[1] = xmlrpc_params;
 955         callback_params[2] = pData->caller_params;
 956 
 957         /* Use same C function for all methods */
 958 
 959         /* php func prototype: function user_func($method_name, $xmlrpc_params, $user_params) */
 960         call_user_function(CG(function_table), NULL, pData->php_function, pData->return_data, 3, callback_params TSRMLS_CC);
 961 
 962         pData->php_executed = 1;
 963 
 964         zval_ptr_dtor(&xmlrpc_params);
 965 
 966         return PHP_to_XMLRPC(pData->return_data TSRMLS_CC);
 967 }
 968 /* }}} */
 969 
 970 /* called by the C server when it first receives an introspection request.  We pass this on to
 971  * our PHP listeners, if any
 972  */
 973 static void php_xmlrpc_introspection_callback(XMLRPC_SERVER server, void* data) /* {{{ */
 974 {
 975         zval retval, **php_function;
 976         zval *callback_params[1];
 977         char *php_function_name;
 978         xmlrpc_callback_data* pData = (xmlrpc_callback_data*)data;
 979         TSRMLS_FETCH();
 980 
 981         /* setup data hoojum */
 982         callback_params[0] = pData->caller_params;
 983 
 984         /* loop through and call all registered callbacks */
 985         zend_hash_internal_pointer_reset(Z_ARRVAL_P(pData->server->introspection_map));
 986         while (1) {
 987                 if (zend_hash_get_current_data(Z_ARRVAL_P(pData->server->introspection_map), (void**)&php_function) == SUCCESS) {
 988                         if (zend_is_callable(*php_function, 0, &php_function_name TSRMLS_CC)) {
 989                                 /* php func prototype: function string user_func($user_params) */
 990                                 if (call_user_function(CG(function_table), NULL, *php_function, &retval, 1, callback_params TSRMLS_CC) == SUCCESS) {
 991                                         XMLRPC_VALUE xData;
 992                                         STRUCT_XMLRPC_ERROR err = {0};
 993 
 994                                         /* return value should be a string */
 995                                         convert_to_string(&retval);
 996 
 997                                         xData = XMLRPC_IntrospectionCreateDescription(Z_STRVAL(retval), &err);
 998 
 999                                         if (xData) {
1000                                                 if (!XMLRPC_ServerAddIntrospectionData(server, xData)) {
1001                                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to add introspection data returned from %s(), improper element structure", php_function_name);
1002                                                 }
1003                                                 XMLRPC_CleanupValue(xData);
1004                                         } else {
1005                                                 /* could not create description */
1006                                                 if (err.xml_elem_error.parser_code) {
1007                                                         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()", 
1008                                                                 err.xml_elem_error.column, err.xml_elem_error.line, err.xml_elem_error.parser_error, php_function_name);
1009                                                 } else {
1010                                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to add introspection data returned from %s()", php_function_name);
1011                                                 }
1012                                         }
1013                                         zval_dtor(&retval);
1014                                 } else {
1015                                         /* user func failed */
1016                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error calling user introspection callback: %s()", php_function_name);
1017                                 }
1018                         } else {
1019                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid callback '%s' passed", php_function_name);
1020                         }
1021                         efree(php_function_name);
1022                 } else {
1023                         break;
1024                 }
1025                 zend_hash_move_forward(Z_ARRVAL_P(pData->server->introspection_map));
1026         }
1027         
1028         /* so we don't call the same callbacks ever again */
1029         zend_hash_clean(Z_ARRVAL_P(pData->server->introspection_map));
1030 }
1031 /* }}} */
1032 
1033 /* {{{ proto bool xmlrpc_server_register_method(resource server, string method_name, string function)
1034    Register a PHP function to handle method matching method_name */
1035 PHP_FUNCTION(xmlrpc_server_register_method)
1036 {
1037         char *method_key;
1038         int method_key_len;
1039         zval *handle, *method_name_save, **method_name;
1040         int type;
1041         xmlrpc_server_data* server;
1042 
1043         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsZ", &handle, &method_key, &method_key_len, &method_name) == FAILURE) {
1044                 return;
1045         }
1046 
1047         server = zend_list_find(Z_LVAL_P(handle), &type);
1048 
1049         if (type == le_xmlrpc_server) {
1050                 /* register with C engine. every method just calls our standard callback, 
1051                  * and it then dispatches to php as necessary
1052                  */
1053                 if (XMLRPC_ServerRegisterMethod(server->server_ptr, method_key, php_xmlrpc_callback)) {
1054                         /* save for later use */
1055                         ALLOC_ZVAL(method_name_save);
1056                         MAKE_COPY_ZVAL(method_name, method_name_save);
1057 
1058                         /* register our php method */
1059                         add_zval(server->method_map, method_key, &method_name_save);
1060 
1061                         RETURN_BOOL(1);
1062                 }
1063         }
1064         RETURN_BOOL(0);
1065 }
1066 /* }}} */
1067 
1068 /* {{{ proto bool xmlrpc_server_register_introspection_callback(resource server, string function)
1069    Register a PHP function to generate documentation */
1070 PHP_FUNCTION(xmlrpc_server_register_introspection_callback)
1071 {
1072         zval **method_name, *handle, *method_name_save;
1073         int type;
1074         xmlrpc_server_data* server;
1075 
1076         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ", &handle, &method_name) == FAILURE) {
1077                 return;
1078         }
1079 
1080         server = zend_list_find(Z_LVAL_P(handle), &type);
1081 
1082         if (type == le_xmlrpc_server) {
1083                 /* save for later use */
1084                 ALLOC_ZVAL(method_name_save);
1085                 MAKE_COPY_ZVAL(method_name, method_name_save);
1086 
1087                 /* register our php method */
1088                 add_zval(server->introspection_map, NULL, &method_name_save);
1089 
1090                 RETURN_BOOL(1);
1091         }
1092         RETURN_BOOL(0);
1093 }
1094 /* }}} */
1095 
1096 /* this function is itchin for a re-write */
1097 
1098 /* {{{ proto mixed xmlrpc_server_call_method(resource server, string xml, mixed user_data [, array output_options])
1099    Parses XML requests and call methods */
1100 PHP_FUNCTION(xmlrpc_server_call_method)
1101 {
1102         xmlrpc_callback_data data = {0};
1103         XMLRPC_REQUEST xRequest;
1104         STRUCT_XMLRPC_REQUEST_INPUT_OPTIONS input_opts;
1105         xmlrpc_server_data* server;
1106         zval **caller_params, *handle, *output_opts = NULL;
1107         char *rawxml;
1108         int rawxml_len, type;
1109         php_output_options out;
1110         int argc =ZEND_NUM_ARGS();
1111         
1112         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsZ|a", &handle, &rawxml, &rawxml_len, &caller_params, &output_opts) != SUCCESS) {
1113                 return;
1114         }
1115         /* user output options */
1116         if (argc == 3) {
1117                 set_output_options(&out, NULL);
1118         } else {
1119                 set_output_options(&out, output_opts);
1120         }
1121 
1122         server = zend_list_find(Z_LVAL_P(handle), &type);
1123 
1124         if (type == le_xmlrpc_server) {
1125                 /* HACK: use output encoding for now */
1126                 input_opts.xml_elem_opts.encoding = utf8_get_encoding_id_from_string(out.xmlrpc_out.xml_elem_opts.encoding);
1127 
1128                 /* generate an XMLRPC_REQUEST from the raw xml input */
1129                 xRequest = XMLRPC_REQUEST_FromXML(rawxml, rawxml_len, &input_opts);
1130 
1131                 if (xRequest) {
1132                         const char* methodname = XMLRPC_RequestGetMethodName(xRequest);
1133                         XMLRPC_VALUE xAnswer = NULL;
1134                         MAKE_STD_ZVAL(data.xmlrpc_method); /* init. very important.  spent a frustrating day finding this out. */
1135                         MAKE_STD_ZVAL(data.return_data);
1136                         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 */
1137                         Z_TYPE_P(data.xmlrpc_method) = IS_NULL;
1138 
1139                         /* setup some data to pass to the callback function */
1140                         data.caller_params = *caller_params;
1141                         data.php_executed = 0;
1142                         data.server = server;
1143 
1144                         /* We could just call the php method directly ourselves at this point, but we do this 
1145                          * with a C callback in case the xmlrpc library ever implements some cool usage stats,
1146                          * or somesuch.
1147                          */
1148                         xAnswer = XMLRPC_ServerCallMethod(server->server_ptr, xRequest, &data);
1149                         if (xAnswer && out.b_php_out) {
1150                                 zval_dtor(data.return_data);
1151                                 FREE_ZVAL(data.return_data);
1152                                 data.return_data = XMLRPC_to_PHP(xAnswer);
1153                         } else if (data.php_executed && !out.b_php_out && !xAnswer) {
1154                                 xAnswer = PHP_to_XMLRPC(data.return_data TSRMLS_CC);
1155                         }
1156 
1157                         /* should we return data as xml? */
1158                         if (!out.b_php_out) {
1159                                 XMLRPC_REQUEST xResponse = XMLRPC_RequestNew();
1160                                 if (xResponse) {
1161                                         char *outBuf = 0;
1162                                         int buf_len = 0;
1163 
1164                                         /* automagically determine output serialization type from request type */
1165                                         if (out.b_auto_version) { 
1166                                                 XMLRPC_REQUEST_OUTPUT_OPTIONS opts = XMLRPC_RequestGetOutputOptions(xRequest);
1167                                                 if (opts) {
1168                                                         out.xmlrpc_out.version = opts->version;
1169                                                 }
1170                                         }
1171                                         /* set some required request hoojum */
1172                                         XMLRPC_RequestSetOutputOptions(xResponse, &out.xmlrpc_out);
1173                                         XMLRPC_RequestSetRequestType(xResponse, xmlrpc_request_response);
1174                                         XMLRPC_RequestSetData(xResponse, xAnswer);
1175                                         XMLRPC_RequestSetMethodName(xResponse, methodname);
1176 
1177                                         /* generate xml */
1178                                         outBuf = XMLRPC_REQUEST_ToXML(xResponse, &buf_len);
1179                                         if (outBuf) {
1180                                                 RETVAL_STRINGL(outBuf, buf_len, 1);
1181                                                 free(outBuf);
1182                                         }
1183                                         /* cleanup after ourselves.  what a sty! */
1184                                         XMLRPC_RequestFree(xResponse, 0);
1185                                 }
1186                         } else { /* or as native php types? */
1187                                 *return_value = *data.return_data;
1188                                 zval_copy_ctor(return_value);
1189                         }
1190 
1191                         /* cleanup after ourselves.  what a sty! */
1192                         zval_ptr_dtor(&data.xmlrpc_method);
1193 
1194                         zval_dtor(data.return_data);
1195                         FREE_ZVAL(data.return_data);
1196 
1197                         if (xAnswer) {
1198                                 XMLRPC_CleanupValue(xAnswer);
1199                         }
1200 
1201                         XMLRPC_RequestFree(xRequest, 1);
1202                 }
1203         }
1204 }
1205 /* }}} */
1206 
1207 /* {{{ proto int xmlrpc_server_add_introspection_data(resource server, array desc)
1208    Adds introspection documentation  */
1209 PHP_FUNCTION(xmlrpc_server_add_introspection_data)
1210 {
1211         zval *handle, *desc;
1212         int type;
1213         xmlrpc_server_data* server;
1214 
1215         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ra", &handle, &desc) == FAILURE) {
1216                 return;
1217         }
1218 
1219         server = zend_list_find(Z_LVAL_P(handle), &type);
1220 
1221         if (type == le_xmlrpc_server) {
1222                 XMLRPC_VALUE xDesc = PHP_to_XMLRPC(desc TSRMLS_CC);
1223                 if (xDesc) {
1224                         int retval = XMLRPC_ServerAddIntrospectionData(server->server_ptr, xDesc);
1225                         XMLRPC_CleanupValue(xDesc);
1226                         RETURN_LONG(retval);
1227                 }
1228         }
1229         RETURN_LONG(0);
1230 }
1231 /* }}} */
1232 
1233 /* {{{ proto array xmlrpc_parse_method_descriptions(string xml)
1234    Decodes XML into a list of method descriptions */
1235 PHP_FUNCTION(xmlrpc_parse_method_descriptions)
1236 {
1237         zval *retval;
1238         char *arg1;
1239         int arg1_len;
1240 
1241         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg1, &arg1_len) == FAILURE) {
1242                 return;
1243         }
1244 
1245         if (return_value_used) {
1246                 STRUCT_XMLRPC_ERROR err = {0};
1247                 XMLRPC_VALUE xVal = XMLRPC_IntrospectionCreateDescription(arg1, &err);
1248                 if (xVal) {
1249                         retval = XMLRPC_to_PHP(xVal);
1250 
1251                         if (retval) {
1252                                 RETVAL_ZVAL(retval, 1, 1);
1253                         }
1254                         /* dust, sweep, and mop */
1255                         XMLRPC_CleanupValue(xVal);
1256                 } else {
1257                         /* could not create description */
1258                         if (err.xml_elem_error.parser_code) {
1259                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "xml parse error: [line %ld, column %ld, message: %s] Unable to create introspection data", 
1260                                                 err.xml_elem_error.column, err.xml_elem_error.line, err.xml_elem_error.parser_error);
1261                         } else {
1262                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid xml structure. Unable to create introspection data");
1263                         }
1264 
1265                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "xml parse error. no method description created");
1266                 }
1267         }
1268 }
1269 /* }}} */
1270 
1271 /************
1272 * type data *
1273 ************/
1274 
1275 #define XMLRPC_TYPE_COUNT 9
1276 #define XMLRPC_VECTOR_TYPE_COUNT 4
1277 #define TYPE_STR_MAP_SIZE (XMLRPC_TYPE_COUNT + XMLRPC_VECTOR_TYPE_COUNT)
1278 
1279 /* return a string matching a given xmlrpc type */
1280 static const char** get_type_str_mapping(void) /* {{{ */
1281 {
1282         static const char* str_mapping[TYPE_STR_MAP_SIZE];
1283         static int first = 1;
1284         if (first) {
1285                 /* warning. do not add/delete without changing size define */
1286                 str_mapping[xmlrpc_none]     = "none";
1287                 str_mapping[xmlrpc_empty]    = "empty";
1288                 str_mapping[xmlrpc_base64]   = "base64";
1289                 str_mapping[xmlrpc_boolean]  = "boolean";
1290                 str_mapping[xmlrpc_datetime] = "datetime";
1291                 str_mapping[xmlrpc_double]   = "double";
1292                 str_mapping[xmlrpc_int]      = "int";
1293                 str_mapping[xmlrpc_string]   = "string";
1294                 str_mapping[xmlrpc_vector]   = "vector";
1295                 str_mapping[XMLRPC_TYPE_COUNT + xmlrpc_vector_none]   = "none";
1296                 str_mapping[XMLRPC_TYPE_COUNT + xmlrpc_vector_array]  = "array";
1297                 str_mapping[XMLRPC_TYPE_COUNT + xmlrpc_vector_mixed]  = "mixed";
1298                 str_mapping[XMLRPC_TYPE_COUNT + xmlrpc_vector_struct] = "struct";
1299                 first = 0;
1300         }
1301         return (const char**)str_mapping;
1302 }
1303 /* }}} */
1304 
1305 /* map an xmlrpc type to a string */
1306 const char* xmlrpc_type_as_str(XMLRPC_VALUE_TYPE type, XMLRPC_VECTOR_TYPE vtype) /* {{{ */
1307 {
1308         const char** str_mapping = get_type_str_mapping();
1309 
1310         if (vtype == xmlrpc_vector_none) {
1311                 return str_mapping[type];
1312         } else {
1313                 return str_mapping[XMLRPC_TYPE_COUNT + vtype];
1314         }
1315 }
1316 /* }}} */
1317 
1318 /* map a string to an xmlrpc type */
1319 XMLRPC_VALUE_TYPE xmlrpc_str_as_type(const char* str) /* {{{ */
1320 {
1321         const char** str_mapping = get_type_str_mapping();
1322         int i;
1323 
1324         if (str) {
1325                 for (i = 0; i < XMLRPC_TYPE_COUNT; i++) {
1326                         if (!strcmp(str_mapping[i], str)) {
1327                                 return (XMLRPC_VALUE_TYPE) i;
1328                         }
1329                 }
1330         }
1331         return xmlrpc_none;
1332 }
1333 /* }}} */
1334 
1335 /* map a string to an xmlrpc vector type */
1336 XMLRPC_VECTOR_TYPE xmlrpc_str_as_vector_type(const char* str) /* {{{ */
1337 {
1338         const char** str_mapping = get_type_str_mapping();
1339         int i;
1340 
1341         if (str) {
1342                 for (i = XMLRPC_TYPE_COUNT; i < TYPE_STR_MAP_SIZE; i++) {
1343                         if (!strcmp(str_mapping[i], str)) {
1344                                 return (XMLRPC_VECTOR_TYPE) (i - XMLRPC_TYPE_COUNT);
1345                         }
1346                 }
1347         }
1348         return xmlrpc_none;
1349 }
1350 /* }}} */
1351 
1352 /* set a given value to a particular type. 
1353  * note: this only works on strings, and only for date and base64,
1354  *       which do not have native php types. black magic lies herein.
1355  */
1356 int set_zval_xmlrpc_type(zval* value, XMLRPC_VALUE_TYPE newtype) /* {{{ */
1357 {
1358         int bSuccess = FAILURE;
1359         TSRMLS_FETCH();
1360 
1361         /* we only really care about strings because they can represent
1362          * base64 and datetime.  all other types have corresponding php types
1363          */
1364         if (Z_TYPE_P(value) == IS_STRING) {
1365                 if (newtype == xmlrpc_base64 || newtype == xmlrpc_datetime) {
1366                         const char* typestr = xmlrpc_type_as_str(newtype, xmlrpc_vector_none);
1367                         zval* type;
1368 
1369                         MAKE_STD_ZVAL(type);
1370 
1371                         Z_TYPE_P(type) = IS_STRING;
1372                         Z_STRVAL_P(type) = estrdup(typestr);
1373                         Z_STRLEN_P(type) = strlen(typestr);
1374 
1375                         if (newtype == xmlrpc_datetime) {
1376                                 XMLRPC_VALUE v = XMLRPC_CreateValueDateTime_ISO8601(NULL, value->value.str.val);
1377                                 if (v) {
1378                                         time_t timestamp = (time_t) php_parse_date((char *)XMLRPC_GetValueDateTime_ISO8601(v), NULL);
1379                                         if (timestamp != -1) {
1380                                                 zval* ztimestamp;
1381 
1382                                                 MAKE_STD_ZVAL(ztimestamp);
1383 
1384                                                 ztimestamp->type = IS_LONG;
1385                                                 ztimestamp->value.lval = timestamp;
1386 
1387                                                 convert_to_object(value);
1388                                                 if (SUCCESS == zend_hash_update(Z_OBJPROP_P(value), OBJECT_TYPE_ATTR, sizeof(OBJECT_TYPE_ATTR), (void *) &type, sizeof(zval *), NULL)) {
1389                                                         bSuccess = zend_hash_update(Z_OBJPROP_P(value), OBJECT_VALUE_TS_ATTR, sizeof(OBJECT_VALUE_TS_ATTR), (void *) &ztimestamp, sizeof(zval *), NULL);
1390                                                 }
1391                                         } else {
1392                                                 zval_ptr_dtor(&type);
1393                                         }
1394                                         XMLRPC_CleanupValue(v);
1395                                 } else {
1396                                         zval_ptr_dtor(&type);
1397                                 }
1398                         } else {
1399                                 convert_to_object(value);
1400                                 bSuccess = zend_hash_update(Z_OBJPROP_P(value), OBJECT_TYPE_ATTR, sizeof(OBJECT_TYPE_ATTR), (void *) &type, sizeof(zval *), NULL);
1401                         }
1402                 }
1403         }
1404 
1405         return bSuccess;
1406 }
1407 /* }}} */
1408 
1409 /* return xmlrpc type of a php value */
1410 XMLRPC_VALUE_TYPE get_zval_xmlrpc_type(zval* value, zval** newvalue) /* {{{ */
1411 {
1412         XMLRPC_VALUE_TYPE type = xmlrpc_none;
1413         TSRMLS_FETCH();
1414 
1415         if (value) {
1416                 switch (Z_TYPE_P(value)) {
1417                         case IS_NULL:
1418                                 type = xmlrpc_base64;
1419                                 break;
1420 #ifndef BOOL_AS_LONG
1421 
1422                         /* Right thing to do, but it breaks some legacy code. */
1423                         case IS_BOOL:
1424                                 type = xmlrpc_boolean;
1425                                 break;
1426 #else
1427                         case IS_BOOL:
1428 #endif
1429                         case IS_LONG:
1430                         case IS_RESOURCE:
1431                                 type = xmlrpc_int;
1432                                 break;
1433                         case IS_DOUBLE:
1434                                 type = xmlrpc_double;
1435                                 break;
1436                         case IS_CONSTANT:
1437                                 type = xmlrpc_string;
1438                                 break;
1439                         case IS_STRING:
1440                                 type = xmlrpc_string;
1441                                 break;
1442                         case IS_ARRAY:
1443                                 type = xmlrpc_vector;
1444                                 break;
1445                         case IS_OBJECT:
1446                                 {
1447                                         zval** attr;
1448                                         type = xmlrpc_vector;
1449 
1450                                         if (zend_hash_find(Z_OBJPROP_P(value), OBJECT_TYPE_ATTR, sizeof(OBJECT_TYPE_ATTR), (void**) &attr) == SUCCESS) {
1451                                                 if (Z_TYPE_PP(attr) == IS_STRING) {
1452                                                         type = xmlrpc_str_as_type(Z_STRVAL_PP(attr));
1453                                                 }
1454                                         }
1455                                         break;
1456                                 }
1457                 }
1458 
1459                 /* if requested, return an unmolested (magic removed) copy of the value */
1460                 if (newvalue) {
1461                         zval** val;
1462 
1463                         if ((type == xmlrpc_base64 && Z_TYPE_P(value) == IS_OBJECT) || type == xmlrpc_datetime) {
1464                                 if (zend_hash_find(Z_OBJPROP_P(value), OBJECT_VALUE_ATTR, sizeof(OBJECT_VALUE_ATTR), (void**) &val) == SUCCESS) {
1465                                         *newvalue = *val;
1466                                 }
1467                         } else {
1468                                 *newvalue = value;
1469                         }
1470                 }
1471         }
1472 
1473         return type;
1474 }
1475 /* }}} */
1476 
1477 /* {{{ proto bool xmlrpc_set_type(string value, string type)
1478    Sets xmlrpc type, base64 or datetime, for a PHP string value */
1479 PHP_FUNCTION(xmlrpc_set_type)
1480 {
1481         zval **arg;
1482         char *type;
1483         int type_len;
1484         XMLRPC_VALUE_TYPE vtype;
1485 
1486         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zs", &arg, &type, &type_len) == FAILURE) {
1487                 return;
1488         }
1489 
1490         vtype = xmlrpc_str_as_type(type);
1491         if (vtype != xmlrpc_none) {
1492                 if (set_zval_xmlrpc_type(*arg, vtype) == SUCCESS) {
1493                         RETURN_TRUE;
1494                 }
1495         } else {
1496                 zend_error(E_WARNING,"invalid type '%s' passed to xmlrpc_set_type()", type);
1497         }
1498         RETURN_FALSE;
1499 }
1500 /* }}} */
1501 
1502 /* {{{ proto string xmlrpc_get_type(mixed value)
1503    Gets xmlrpc type for a PHP value. Especially useful for base64 and datetime strings */
1504 PHP_FUNCTION(xmlrpc_get_type)
1505 {
1506         zval **arg;
1507         XMLRPC_VALUE_TYPE type;
1508         XMLRPC_VECTOR_TYPE vtype = xmlrpc_vector_none;
1509 
1510         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg) == FAILURE) {
1511                 return;
1512         }
1513 
1514         type = get_zval_xmlrpc_type(*arg, 0);
1515         if (type == xmlrpc_vector) {
1516                 vtype = determine_vector_type((Z_TYPE_PP(arg) == IS_OBJECT) ? Z_OBJPROP_PP(arg) : Z_ARRVAL_PP(arg));
1517         }
1518    
1519         RETURN_STRING((char*) xmlrpc_type_as_str(type, vtype), 1);
1520 }
1521 /* }}} */
1522 
1523 /* {{{ proto bool xmlrpc_is_fault(array)
1524    Determines if an array value represents an XMLRPC fault. */
1525 PHP_FUNCTION(xmlrpc_is_fault)
1526 {
1527         zval *arg, **val;
1528 
1529         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &arg) == FAILURE) {
1530                 return;
1531         }
1532 
1533         /* The "correct" way to do this would be to call the xmlrpc
1534          * library XMLRPC_ValueIsFault() func.  However, doing that
1535          * would require us to create an xmlrpc value from the php
1536          * array, which is rather expensive, especially if it was
1537          * a big array.  Thus, we resort to this not so clever hackery.
1538          */
1539         if (zend_hash_find(Z_ARRVAL_P(arg), FAULT_CODE, FAULT_CODE_LEN + 1, (void**) &val) == SUCCESS && 
1540                 zend_hash_find(Z_ARRVAL_P(arg), FAULT_STRING, FAULT_STRING_LEN + 1, (void**) &val) == SUCCESS) {
1541                 RETURN_TRUE;
1542         }
1543 
1544         RETURN_FALSE;
1545 }
1546 /* }}} */
1547 
1548 /*
1549  * Local variables:
1550  * tab-width: 4
1551  * c-basic-offset: 4
1552  * End:
1553  */
1554 

/* [<][>][^][v][top][bottom][index][help] */