Annotation of embedaddon/php/ext/xmlrpc/xmlrpc-epi-php.c, revision 1.1
1.1 ! misho 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-2012 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 321634 2012-01-01 13:15:04Z felipe $ */
! 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_EXISTANT) {
! 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: xReturn = XMLRPC_CreateValueBase64(key, Z_STRVAL_P(val), Z_STRLEN_P(val));
! 536: }
! 537: break;
! 538: case xmlrpc_datetime:
! 539: convert_to_string(val);
! 540: xReturn = XMLRPC_CreateValueDateTime_ISO8601(key, Z_STRVAL_P(val));
! 541: break;
! 542: case xmlrpc_boolean:
! 543: convert_to_boolean(val);
! 544: xReturn = XMLRPC_CreateValueBoolean(key, Z_LVAL_P(val));
! 545: break;
! 546: case xmlrpc_int:
! 547: convert_to_long(val);
! 548: xReturn = XMLRPC_CreateValueInt(key, Z_LVAL_P(val));
! 549: break;
! 550: case xmlrpc_double:
! 551: convert_to_double(val);
! 552: xReturn = XMLRPC_CreateValueDouble(key, Z_DVAL_P(val));
! 553: break;
! 554: case xmlrpc_string:
! 555: convert_to_string(val);
! 556: xReturn = XMLRPC_CreateValueString(key, Z_STRVAL_P(val), Z_STRLEN_P(val));
! 557: break;
! 558: case xmlrpc_vector:
! 559: {
! 560: unsigned long num_index;
! 561: zval** pIter;
! 562: char* my_key;
! 563: HashTable *ht = NULL;
! 564: zval *val_arr;
! 565: XMLRPC_VECTOR_TYPE vtype;
! 566:
! 567: ht = HASH_OF(val);
! 568: if (ht && ht->nApplyCount > 1) {
! 569: php_error_docref(NULL TSRMLS_CC, E_ERROR, "XML-RPC doesn't support circular references");
! 570: return NULL;
! 571: }
! 572:
! 573: MAKE_STD_ZVAL(val_arr);
! 574: MAKE_COPY_ZVAL(&val, val_arr);
! 575: convert_to_array(val_arr);
! 576:
! 577: vtype = determine_vector_type(Z_ARRVAL_P(val_arr));
! 578: xReturn = XMLRPC_CreateVector(key, vtype);
! 579:
! 580: zend_hash_internal_pointer_reset(Z_ARRVAL_P(val_arr));
! 581: while(zend_hash_get_current_data(Z_ARRVAL_P(val_arr), (void**)&pIter) == SUCCESS) {
! 582: int res = my_zend_hash_get_current_key(Z_ARRVAL_P(val_arr), &my_key, &num_index);
! 583:
! 584: switch (res) {
! 585: case HASH_KEY_NON_EXISTANT:
! 586: break;
! 587: case HASH_KEY_IS_STRING:
! 588: case HASH_KEY_IS_LONG:
! 589: ht = HASH_OF(*pIter);
! 590: if (ht) {
! 591: ht->nApplyCount++;
! 592: }
! 593: if (res == HASH_KEY_IS_LONG) {
! 594: char *num_str = NULL;
! 595:
! 596: if (vtype != xmlrpc_vector_array) {
! 597: spprintf(&num_str, 0, "%ld", num_index);
! 598: }
! 599: XMLRPC_AddValueToVector(xReturn, PHP_to_XMLRPC_worker(num_str, *pIter, depth++ TSRMLS_CC));
! 600: if (num_str) {
! 601: efree(num_str);
! 602: }
! 603: } else {
! 604: XMLRPC_AddValueToVector(xReturn, PHP_to_XMLRPC_worker(my_key, *pIter, depth++ TSRMLS_CC));
! 605: }
! 606: if (ht) {
! 607: ht->nApplyCount--;
! 608: }
! 609: break;
! 610: }
! 611: zend_hash_move_forward(Z_ARRVAL_P(val_arr));
! 612: }
! 613: zval_ptr_dtor(&val_arr);
! 614: }
! 615: break;
! 616: default:
! 617: break;
! 618: }
! 619: }
! 620: }
! 621: return xReturn;
! 622: }
! 623:
! 624: static XMLRPC_VALUE PHP_to_XMLRPC(zval* root_val TSRMLS_DC)
! 625: {
! 626: return PHP_to_XMLRPC_worker(NULL, root_val, 0 TSRMLS_CC);
! 627: }
! 628:
! 629: /* recursively convert xmlrpc values into php values */
! 630: static zval* XMLRPC_to_PHP(XMLRPC_VALUE el)
! 631: {
! 632: zval* elem = NULL;
! 633: const char* pStr;
! 634:
! 635: if (el) {
! 636: XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(el);
! 637:
! 638: MAKE_STD_ZVAL(elem); /* init. very important. spent a frustrating day finding this out. */
! 639:
! 640: switch(type) {
! 641: case xmlrpc_empty:
! 642: Z_TYPE_P(elem) = IS_NULL;
! 643: break;
! 644: case xmlrpc_string:
! 645: pStr = XMLRPC_GetValueString(el);
! 646: if (pStr) {
! 647: Z_STRLEN_P(elem) = XMLRPC_GetValueStringLen(el);
! 648: Z_STRVAL_P(elem) = estrndup(pStr, Z_STRLEN_P(elem));
! 649: Z_TYPE_P(elem) = IS_STRING;
! 650: }
! 651: break;
! 652: case xmlrpc_int:
! 653: Z_LVAL_P(elem) = XMLRPC_GetValueInt(el);
! 654: Z_TYPE_P(elem) = IS_LONG;
! 655: break;
! 656: case xmlrpc_boolean:
! 657: Z_LVAL_P(elem) = XMLRPC_GetValueBoolean(el);
! 658: Z_TYPE_P(elem) = IS_BOOL;
! 659: break;
! 660: case xmlrpc_double:
! 661: Z_DVAL_P(elem) = XMLRPC_GetValueDouble(el);
! 662: Z_TYPE_P(elem) = IS_DOUBLE;
! 663: break;
! 664: case xmlrpc_datetime:
! 665: Z_STRLEN_P(elem) = XMLRPC_GetValueStringLen(el);
! 666: Z_STRVAL_P(elem) = estrndup(XMLRPC_GetValueDateTime_ISO8601(el), Z_STRLEN_P(elem));
! 667: Z_TYPE_P(elem) = IS_STRING;
! 668: break;
! 669: case xmlrpc_base64:
! 670: pStr = XMLRPC_GetValueBase64(el);
! 671: if (pStr) {
! 672: Z_STRLEN_P(elem) = XMLRPC_GetValueStringLen(el);
! 673: Z_STRVAL_P(elem) = estrndup(pStr, Z_STRLEN_P(elem));
! 674: Z_TYPE_P(elem) = IS_STRING;
! 675: }
! 676: break;
! 677: case xmlrpc_vector:
! 678: array_init(elem);
! 679: {
! 680: XMLRPC_VALUE xIter = XMLRPC_VectorRewind(el);
! 681:
! 682: while( xIter ) {
! 683: zval *val = XMLRPC_to_PHP(xIter);
! 684: if (val) {
! 685: add_zval(elem, XMLRPC_GetValueID(xIter), &val);
! 686: }
! 687: xIter = XMLRPC_VectorNext(el);
! 688: }
! 689: }
! 690: break;
! 691: default:
! 692: break;
! 693: }
! 694: set_zval_xmlrpc_type(elem, type);
! 695: }
! 696: return elem;
! 697: }
! 698:
! 699: /* {{{ proto string xmlrpc_encode_request(string method, mixed params [, array output_options])
! 700: Generates XML for a method request */
! 701: PHP_FUNCTION(xmlrpc_encode_request)
! 702: {
! 703: XMLRPC_REQUEST xRequest = NULL;
! 704: char *outBuf;
! 705: zval *vals, *out_opts = NULL;
! 706: char *method = NULL;
! 707: int method_len;
! 708: php_output_options out;
! 709:
! 710: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!z|a", &method, &method_len, &vals, &out_opts) == FAILURE) {
! 711: return;
! 712: }
! 713:
! 714: set_output_options(&out, out_opts ? out_opts : 0);
! 715:
! 716: if (return_value_used) {
! 717: xRequest = XMLRPC_RequestNew();
! 718:
! 719: if (xRequest) {
! 720: XMLRPC_RequestSetOutputOptions(xRequest, &out.xmlrpc_out);
! 721: if (method == NULL) {
! 722: XMLRPC_RequestSetRequestType(xRequest, xmlrpc_request_response);
! 723: } else {
! 724: XMLRPC_RequestSetMethodName(xRequest, method);
! 725: XMLRPC_RequestSetRequestType(xRequest, xmlrpc_request_call);
! 726: }
! 727: if (Z_TYPE_P(vals) != IS_NULL) {
! 728: XMLRPC_RequestSetData(xRequest, PHP_to_XMLRPC(vals TSRMLS_CC));
! 729: }
! 730:
! 731: outBuf = XMLRPC_REQUEST_ToXML(xRequest, 0);
! 732: if (outBuf) {
! 733: RETVAL_STRING(outBuf, 1);
! 734: free(outBuf);
! 735: }
! 736: XMLRPC_RequestFree(xRequest, 1);
! 737: }
! 738: }
! 739:
! 740: if (strcmp(out.xmlrpc_out.xml_elem_opts.encoding, ENCODING_DEFAULT) != 0) {
! 741: efree((char *)out.xmlrpc_out.xml_elem_opts.encoding);
! 742: }
! 743: }
! 744: /* }}} */
! 745:
! 746: /* {{{ proto string xmlrpc_encode(mixed value)
! 747: Generates XML for a PHP value */
! 748: PHP_FUNCTION(xmlrpc_encode)
! 749: {
! 750: XMLRPC_VALUE xOut = NULL;
! 751: zval **arg1;
! 752: char *outBuf;
! 753:
! 754: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg1) == FAILURE) {
! 755: return;
! 756: }
! 757:
! 758: if (return_value_used) {
! 759: /* convert native php type to xmlrpc type */
! 760: xOut = PHP_to_XMLRPC(*arg1 TSRMLS_CC);
! 761:
! 762: /* generate raw xml from xmlrpc data */
! 763: outBuf = XMLRPC_VALUE_ToXML(xOut, 0);
! 764:
! 765: if (xOut) {
! 766: if (outBuf) {
! 767: RETVAL_STRING(outBuf, 1);
! 768: free(outBuf);
! 769: }
! 770: /* cleanup */
! 771: XMLRPC_CleanupValue(xOut);
! 772: }
! 773: }
! 774: }
! 775: /* }}} */
! 776:
! 777: zval* decode_request_worker(char *xml_in, int xml_in_len, char *encoding_in, zval* method_name_out) /* {{{ */
! 778: {
! 779: zval* retval = NULL;
! 780: XMLRPC_REQUEST response;
! 781: STRUCT_XMLRPC_REQUEST_INPUT_OPTIONS opts = {{0}};
! 782: const char *method_name;
! 783: opts.xml_elem_opts.encoding = encoding_in ? utf8_get_encoding_id_from_string(encoding_in) : ENCODING_DEFAULT;
! 784:
! 785: /* generate XMLRPC_REQUEST from raw xml */
! 786: response = XMLRPC_REQUEST_FromXML(xml_in, xml_in_len, &opts);
! 787: if (response) {
! 788: /* convert xmlrpc data to native php types */
! 789: retval = XMLRPC_to_PHP(XMLRPC_RequestGetData(response));
! 790:
! 791: if (XMLRPC_RequestGetRequestType(response) == xmlrpc_request_call) {
! 792: if (method_name_out) {
! 793: method_name = XMLRPC_RequestGetMethodName(response);
! 794: if (method_name) {
! 795: zval_dtor(method_name_out);
! 796: Z_TYPE_P(method_name_out) = IS_STRING;
! 797: Z_STRVAL_P(method_name_out) = estrdup(method_name);
! 798: Z_STRLEN_P(method_name_out) = strlen(Z_STRVAL_P(method_name_out));
! 799: } else if (retval) {
! 800: zval_ptr_dtor(&retval);
! 801: retval = NULL;
! 802: }
! 803: }
! 804: }
! 805:
! 806: /* dust, sweep, and mop */
! 807: XMLRPC_RequestFree(response, 1);
! 808: }
! 809: return retval;
! 810: }
! 811: /* }}} */
! 812:
! 813: /* {{{ proto array xmlrpc_decode_request(string xml, string& method [, string encoding])
! 814: Decodes XML into native PHP types */
! 815: PHP_FUNCTION(xmlrpc_decode_request)
! 816: {
! 817: char *xml, *encoding = NULL;
! 818: zval **method;
! 819: int xml_len, encoding_len = 0;
! 820:
! 821: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sZ|s", &xml, &xml_len, &method, &encoding, &encoding_len) == FAILURE) {
! 822: return;
! 823: }
! 824:
! 825:
! 826: if (return_value_used) {
! 827: zval* retval = decode_request_worker(xml, xml_len, encoding_len ? encoding : NULL, *method);
! 828: if (retval) {
! 829: *return_value = *retval;
! 830: FREE_ZVAL(retval);
! 831: }
! 832: }
! 833: }
! 834: /* }}} */
! 835:
! 836: /* {{{ proto array xmlrpc_decode(string xml [, string encoding])
! 837: Decodes XML into native PHP types */
! 838: PHP_FUNCTION(xmlrpc_decode)
! 839: {
! 840: char *arg1, *arg2 = NULL;
! 841: int arg1_len, arg2_len = 0;
! 842:
! 843: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &arg1, &arg1_len, &arg2, &arg2_len) == FAILURE) {
! 844: return;
! 845: }
! 846:
! 847: if (return_value_used) {
! 848: zval* retval = decode_request_worker(arg1, arg1_len, arg2_len ? arg2 : NULL, NULL);
! 849: if (retval) {
! 850: *return_value = *retval;
! 851: FREE_ZVAL(retval);
! 852: }
! 853: }
! 854: }
! 855: /* }}} */
! 856:
! 857: /*************************
! 858: * server related methods *
! 859: *************************/
! 860:
! 861: /* {{{ proto resource xmlrpc_server_create(void)
! 862: Creates an xmlrpc server */
! 863: PHP_FUNCTION(xmlrpc_server_create)
! 864: {
! 865: if (zend_parse_parameters_none() == FAILURE) {
! 866: return;
! 867: }
! 868:
! 869: if (return_value_used) {
! 870: zval *method_map, *introspection_map;
! 871: xmlrpc_server_data *server = emalloc(sizeof(xmlrpc_server_data));
! 872: MAKE_STD_ZVAL(method_map);
! 873: MAKE_STD_ZVAL(introspection_map);
! 874:
! 875: array_init(method_map);
! 876: array_init(introspection_map);
! 877:
! 878: /* allocate server data. free'd in destroy_server_data() */
! 879: server->method_map = method_map;
! 880: server->introspection_map = introspection_map;
! 881: server->server_ptr = XMLRPC_ServerCreate();
! 882:
! 883: XMLRPC_ServerRegisterIntrospectionCallback(server->server_ptr, php_xmlrpc_introspection_callback);
! 884:
! 885: /* store for later use */
! 886: ZEND_REGISTER_RESOURCE(return_value,server, le_xmlrpc_server);
! 887: }
! 888: }
! 889: /* }}} */
! 890:
! 891: /* {{{ proto int xmlrpc_server_destroy(resource server)
! 892: Destroys server resources */
! 893: PHP_FUNCTION(xmlrpc_server_destroy)
! 894: {
! 895: zval *arg1;
! 896: int bSuccess = FAILURE, type;
! 897: xmlrpc_server_data *server;
! 898:
! 899: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) {
! 900: return;
! 901: }
! 902:
! 903: server = zend_list_find(Z_LVAL_P(arg1), &type);
! 904:
! 905: if (server && type == le_xmlrpc_server) {
! 906: bSuccess = zend_list_delete(Z_LVAL_P(arg1));
! 907:
! 908: /* called by hashtable destructor
! 909: * destroy_server_data(server);
! 910: */
! 911: }
! 912: RETVAL_LONG(bSuccess == SUCCESS);
! 913: }
! 914: /* }}} */
! 915:
! 916: /* called by xmlrpc C engine as method handler for all registered methods.
! 917: * it then calls the corresponding PHP function to handle the method.
! 918: */
! 919: static XMLRPC_VALUE php_xmlrpc_callback(XMLRPC_SERVER server, XMLRPC_REQUEST xRequest, void* data) /* {{{ */
! 920: {
! 921: xmlrpc_callback_data* pData = (xmlrpc_callback_data*)data;
! 922: zval** php_function;
! 923: zval* xmlrpc_params;
! 924: zval* callback_params[3];
! 925: TSRMLS_FETCH();
! 926:
! 927: zval_dtor(pData->xmlrpc_method);
! 928: zval_dtor(pData->return_data);
! 929:
! 930: /* convert xmlrpc to native php types */
! 931: ZVAL_STRING(pData->xmlrpc_method, XMLRPC_RequestGetMethodName(xRequest), 1);
! 932: xmlrpc_params = XMLRPC_to_PHP(XMLRPC_RequestGetData(xRequest));
! 933:
! 934: /* check if the called method has been previous registered */
! 935: if(zend_hash_find(Z_ARRVAL_P(pData->server->method_map),
! 936: Z_STRVAL_P(pData->xmlrpc_method),
! 937: Z_STRLEN_P(pData->xmlrpc_method) + 1,
! 938: (void**)&php_function) == SUCCESS) {
! 939:
! 940: pData->php_function = *php_function;
! 941: }
! 942:
! 943: /* setup data hoojum */
! 944: callback_params[0] = pData->xmlrpc_method;
! 945: callback_params[1] = xmlrpc_params;
! 946: callback_params[2] = pData->caller_params;
! 947:
! 948: /* Use same C function for all methods */
! 949:
! 950: /* php func prototype: function user_func($method_name, $xmlrpc_params, $user_params) */
! 951: call_user_function(CG(function_table), NULL, pData->php_function, pData->return_data, 3, callback_params TSRMLS_CC);
! 952:
! 953: pData->php_executed = 1;
! 954:
! 955: zval_ptr_dtor(&xmlrpc_params);
! 956:
! 957: return PHP_to_XMLRPC(pData->return_data TSRMLS_CC);
! 958: }
! 959: /* }}} */
! 960:
! 961: /* called by the C server when it first receives an introspection request. We pass this on to
! 962: * our PHP listeners, if any
! 963: */
! 964: static void php_xmlrpc_introspection_callback(XMLRPC_SERVER server, void* data) /* {{{ */
! 965: {
! 966: zval retval, **php_function;
! 967: zval *callback_params[1];
! 968: char *php_function_name;
! 969: xmlrpc_callback_data* pData = (xmlrpc_callback_data*)data;
! 970: TSRMLS_FETCH();
! 971:
! 972: /* setup data hoojum */
! 973: callback_params[0] = pData->caller_params;
! 974:
! 975: /* loop through and call all registered callbacks */
! 976: zend_hash_internal_pointer_reset(Z_ARRVAL_P(pData->server->introspection_map));
! 977: while (1) {
! 978: if (zend_hash_get_current_data(Z_ARRVAL_P(pData->server->introspection_map), (void**)&php_function) == SUCCESS) {
! 979: if (zend_is_callable(*php_function, 0, &php_function_name TSRMLS_CC)) {
! 980: /* php func prototype: function string user_func($user_params) */
! 981: if (call_user_function(CG(function_table), NULL, *php_function, &retval, 1, callback_params TSRMLS_CC) == SUCCESS) {
! 982: XMLRPC_VALUE xData;
! 983: STRUCT_XMLRPC_ERROR err = {0};
! 984:
! 985: /* return value should be a string */
! 986: convert_to_string(&retval);
! 987:
! 988: xData = XMLRPC_IntrospectionCreateDescription(Z_STRVAL(retval), &err);
! 989:
! 990: if (xData) {
! 991: if (!XMLRPC_ServerAddIntrospectionData(server, xData)) {
! 992: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to add introspection data returned from %s(), improper element structure", php_function_name);
! 993: }
! 994: XMLRPC_CleanupValue(xData);
! 995: } else {
! 996: /* could not create description */
! 997: if (err.xml_elem_error.parser_code) {
! 998: 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()",
! 999: err.xml_elem_error.column, err.xml_elem_error.line, err.xml_elem_error.parser_error, php_function_name);
! 1000: } else {
! 1001: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to add introspection data returned from %s()", php_function_name);
! 1002: }
! 1003: }
! 1004: zval_dtor(&retval);
! 1005: } else {
! 1006: /* user func failed */
! 1007: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error calling user introspection callback: %s()", php_function_name);
! 1008: }
! 1009: } else {
! 1010: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid callback '%s' passed", php_function_name);
! 1011: }
! 1012: efree(php_function_name);
! 1013: } else {
! 1014: break;
! 1015: }
! 1016: zend_hash_move_forward(Z_ARRVAL_P(pData->server->introspection_map));
! 1017: }
! 1018:
! 1019: /* so we don't call the same callbacks ever again */
! 1020: zend_hash_clean(Z_ARRVAL_P(pData->server->introspection_map));
! 1021: }
! 1022: /* }}} */
! 1023:
! 1024: /* {{{ proto bool xmlrpc_server_register_method(resource server, string method_name, string function)
! 1025: Register a PHP function to handle method matching method_name */
! 1026: PHP_FUNCTION(xmlrpc_server_register_method)
! 1027: {
! 1028: char *method_key;
! 1029: int method_key_len;
! 1030: zval *handle, *method_name_save, **method_name;
! 1031: int type;
! 1032: xmlrpc_server_data* server;
! 1033:
! 1034: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsZ", &handle, &method_key, &method_key_len, &method_name) == FAILURE) {
! 1035: return;
! 1036: }
! 1037:
! 1038: server = zend_list_find(Z_LVAL_P(handle), &type);
! 1039:
! 1040: if (type == le_xmlrpc_server) {
! 1041: /* register with C engine. every method just calls our standard callback,
! 1042: * and it then dispatches to php as necessary
! 1043: */
! 1044: if (XMLRPC_ServerRegisterMethod(server->server_ptr, method_key, php_xmlrpc_callback)) {
! 1045: /* save for later use */
! 1046: MAKE_STD_ZVAL(method_name_save);
! 1047: *method_name_save = **method_name;
! 1048: zval_copy_ctor(method_name_save);
! 1049:
! 1050: /* register our php method */
! 1051: add_zval(server->method_map, method_key, &method_name_save);
! 1052:
! 1053: RETURN_BOOL(1);
! 1054: }
! 1055: }
! 1056: RETURN_BOOL(0);
! 1057: }
! 1058: /* }}} */
! 1059:
! 1060: /* {{{ proto bool xmlrpc_server_register_introspection_callback(resource server, string function)
! 1061: Register a PHP function to generate documentation */
! 1062: PHP_FUNCTION(xmlrpc_server_register_introspection_callback)
! 1063: {
! 1064: zval **method_name, *handle, *method_name_save;
! 1065: int type;
! 1066: xmlrpc_server_data* server;
! 1067:
! 1068: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ", &handle, &method_name) == FAILURE) {
! 1069: return;
! 1070: }
! 1071:
! 1072: server = zend_list_find(Z_LVAL_P(handle), &type);
! 1073:
! 1074: if (type == le_xmlrpc_server) {
! 1075: /* save for later use */
! 1076: MAKE_STD_ZVAL(method_name_save);
! 1077: *method_name_save = **method_name;
! 1078: zval_copy_ctor(method_name_save);
! 1079:
! 1080: /* register our php method */
! 1081: add_zval(server->introspection_map, NULL, &method_name_save);
! 1082:
! 1083: RETURN_BOOL(1);
! 1084: }
! 1085: RETURN_BOOL(0);
! 1086: }
! 1087: /* }}} */
! 1088:
! 1089: /* this function is itchin for a re-write */
! 1090:
! 1091: /* {{{ proto mixed xmlrpc_server_call_method(resource server, string xml, mixed user_data [, array output_options])
! 1092: Parses XML requests and call methods */
! 1093: PHP_FUNCTION(xmlrpc_server_call_method)
! 1094: {
! 1095: xmlrpc_callback_data data = {0};
! 1096: XMLRPC_REQUEST xRequest;
! 1097: STRUCT_XMLRPC_REQUEST_INPUT_OPTIONS input_opts;
! 1098: xmlrpc_server_data* server;
! 1099: zval **caller_params, *handle, *output_opts = NULL;
! 1100: char *rawxml;
! 1101: int rawxml_len, type;
! 1102: php_output_options out;
! 1103: int argc =ZEND_NUM_ARGS();
! 1104:
! 1105: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsZ|a", &handle, &rawxml, &rawxml_len, &caller_params, &output_opts) != SUCCESS) {
! 1106: return;
! 1107: }
! 1108: /* user output options */
! 1109: if (argc == 3) {
! 1110: set_output_options(&out, NULL);
! 1111: } else {
! 1112: set_output_options(&out, output_opts);
! 1113: }
! 1114:
! 1115: server = zend_list_find(Z_LVAL_P(handle), &type);
! 1116:
! 1117: if (type == le_xmlrpc_server) {
! 1118: /* HACK: use output encoding for now */
! 1119: input_opts.xml_elem_opts.encoding = utf8_get_encoding_id_from_string(out.xmlrpc_out.xml_elem_opts.encoding);
! 1120:
! 1121: /* generate an XMLRPC_REQUEST from the raw xml input */
! 1122: xRequest = XMLRPC_REQUEST_FromXML(rawxml, rawxml_len, &input_opts);
! 1123:
! 1124: if (xRequest) {
! 1125: const char* methodname = XMLRPC_RequestGetMethodName(xRequest);
! 1126: XMLRPC_VALUE xAnswer = NULL;
! 1127: MAKE_STD_ZVAL(data.xmlrpc_method); /* init. very important. spent a frustrating day finding this out. */
! 1128: MAKE_STD_ZVAL(data.return_data);
! 1129: 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 */
! 1130: Z_TYPE_P(data.xmlrpc_method) = IS_NULL;
! 1131:
! 1132: /* setup some data to pass to the callback function */
! 1133: data.caller_params = *caller_params;
! 1134: data.php_executed = 0;
! 1135: data.server = server;
! 1136:
! 1137: /* We could just call the php method directly ourselves at this point, but we do this
! 1138: * with a C callback in case the xmlrpc library ever implements some cool usage stats,
! 1139: * or somesuch.
! 1140: */
! 1141: xAnswer = XMLRPC_ServerCallMethod(server->server_ptr, xRequest, &data);
! 1142: if (xAnswer && out.b_php_out) {
! 1143: zval_dtor(data.return_data);
! 1144: FREE_ZVAL(data.return_data);
! 1145: data.return_data = XMLRPC_to_PHP(xAnswer);
! 1146: } else if (data.php_executed && !out.b_php_out && !xAnswer) {
! 1147: xAnswer = PHP_to_XMLRPC(data.return_data TSRMLS_CC);
! 1148: }
! 1149:
! 1150: /* should we return data as xml? */
! 1151: if (!out.b_php_out) {
! 1152: XMLRPC_REQUEST xResponse = XMLRPC_RequestNew();
! 1153: if (xResponse) {
! 1154: char *outBuf = 0;
! 1155: int buf_len = 0;
! 1156:
! 1157: /* automagically determine output serialization type from request type */
! 1158: if (out.b_auto_version) {
! 1159: XMLRPC_REQUEST_OUTPUT_OPTIONS opts = XMLRPC_RequestGetOutputOptions(xRequest);
! 1160: if (opts) {
! 1161: out.xmlrpc_out.version = opts->version;
! 1162: }
! 1163: }
! 1164: /* set some required request hoojum */
! 1165: XMLRPC_RequestSetOutputOptions(xResponse, &out.xmlrpc_out);
! 1166: XMLRPC_RequestSetRequestType(xResponse, xmlrpc_request_response);
! 1167: XMLRPC_RequestSetData(xResponse, xAnswer);
! 1168: XMLRPC_RequestSetMethodName(xResponse, methodname);
! 1169:
! 1170: /* generate xml */
! 1171: outBuf = XMLRPC_REQUEST_ToXML(xResponse, &buf_len);
! 1172: if (outBuf) {
! 1173: RETVAL_STRINGL(outBuf, buf_len, 1);
! 1174: free(outBuf);
! 1175: }
! 1176: /* cleanup after ourselves. what a sty! */
! 1177: XMLRPC_RequestFree(xResponse, 0);
! 1178: }
! 1179: } else { /* or as native php types? */
! 1180: *return_value = *data.return_data;
! 1181: zval_copy_ctor(return_value);
! 1182: }
! 1183:
! 1184: /* cleanup after ourselves. what a sty! */
! 1185: zval_ptr_dtor(&data.xmlrpc_method);
! 1186:
! 1187: zval_dtor(data.return_data);
! 1188: FREE_ZVAL(data.return_data);
! 1189:
! 1190: if (xAnswer) {
! 1191: XMLRPC_CleanupValue(xAnswer);
! 1192: }
! 1193:
! 1194: XMLRPC_RequestFree(xRequest, 1);
! 1195: }
! 1196: }
! 1197: }
! 1198: /* }}} */
! 1199:
! 1200: /* {{{ proto int xmlrpc_server_add_introspection_data(resource server, array desc)
! 1201: Adds introspection documentation */
! 1202: PHP_FUNCTION(xmlrpc_server_add_introspection_data)
! 1203: {
! 1204: zval *handle, *desc;
! 1205: int type;
! 1206: xmlrpc_server_data* server;
! 1207:
! 1208: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ra", &handle, &desc) == FAILURE) {
! 1209: return;
! 1210: }
! 1211:
! 1212: server = zend_list_find(Z_LVAL_P(handle), &type);
! 1213:
! 1214: if (type == le_xmlrpc_server) {
! 1215: XMLRPC_VALUE xDesc = PHP_to_XMLRPC(desc TSRMLS_CC);
! 1216: if (xDesc) {
! 1217: int retval = XMLRPC_ServerAddIntrospectionData(server->server_ptr, xDesc);
! 1218: XMLRPC_CleanupValue(xDesc);
! 1219: RETURN_LONG(retval);
! 1220: }
! 1221: }
! 1222: RETURN_LONG(0);
! 1223: }
! 1224: /* }}} */
! 1225:
! 1226: /* {{{ proto array xmlrpc_parse_method_descriptions(string xml)
! 1227: Decodes XML into a list of method descriptions */
! 1228: PHP_FUNCTION(xmlrpc_parse_method_descriptions)
! 1229: {
! 1230: zval *retval;
! 1231: char *arg1;
! 1232: int arg1_len;
! 1233:
! 1234: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg1, &arg1_len) == FAILURE) {
! 1235: return;
! 1236: }
! 1237:
! 1238: if (return_value_used) {
! 1239: STRUCT_XMLRPC_ERROR err = {0};
! 1240: XMLRPC_VALUE xVal = XMLRPC_IntrospectionCreateDescription(arg1, &err);
! 1241: if (xVal) {
! 1242: retval = XMLRPC_to_PHP(xVal);
! 1243:
! 1244: if (retval) {
! 1245: *return_value = *retval;
! 1246: zval_copy_ctor(return_value);
! 1247: }
! 1248: /* dust, sweep, and mop */
! 1249: XMLRPC_CleanupValue(xVal);
! 1250: } else {
! 1251: /* could not create description */
! 1252: if (err.xml_elem_error.parser_code) {
! 1253: php_error_docref(NULL TSRMLS_CC, E_WARNING, "xml parse error: [line %ld, column %ld, message: %s] Unable to create introspection data",
! 1254: err.xml_elem_error.column, err.xml_elem_error.line, err.xml_elem_error.parser_error);
! 1255: } else {
! 1256: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid xml structure. Unable to create introspection data");
! 1257: }
! 1258:
! 1259: php_error_docref(NULL TSRMLS_CC, E_WARNING, "xml parse error. no method description created");
! 1260: }
! 1261: }
! 1262: }
! 1263: /* }}} */
! 1264:
! 1265: /************
! 1266: * type data *
! 1267: ************/
! 1268:
! 1269: #define XMLRPC_TYPE_COUNT 9
! 1270: #define XMLRPC_VECTOR_TYPE_COUNT 4
! 1271: #define TYPE_STR_MAP_SIZE (XMLRPC_TYPE_COUNT + XMLRPC_VECTOR_TYPE_COUNT)
! 1272:
! 1273: /* return a string matching a given xmlrpc type */
! 1274: static const char** get_type_str_mapping(void) /* {{{ */
! 1275: {
! 1276: static const char* str_mapping[TYPE_STR_MAP_SIZE];
! 1277: static int first = 1;
! 1278: if (first) {
! 1279: /* warning. do not add/delete without changing size define */
! 1280: str_mapping[xmlrpc_none] = "none";
! 1281: str_mapping[xmlrpc_empty] = "empty";
! 1282: str_mapping[xmlrpc_base64] = "base64";
! 1283: str_mapping[xmlrpc_boolean] = "boolean";
! 1284: str_mapping[xmlrpc_datetime] = "datetime";
! 1285: str_mapping[xmlrpc_double] = "double";
! 1286: str_mapping[xmlrpc_int] = "int";
! 1287: str_mapping[xmlrpc_string] = "string";
! 1288: str_mapping[xmlrpc_vector] = "vector";
! 1289: str_mapping[XMLRPC_TYPE_COUNT + xmlrpc_vector_none] = "none";
! 1290: str_mapping[XMLRPC_TYPE_COUNT + xmlrpc_vector_array] = "array";
! 1291: str_mapping[XMLRPC_TYPE_COUNT + xmlrpc_vector_mixed] = "mixed";
! 1292: str_mapping[XMLRPC_TYPE_COUNT + xmlrpc_vector_struct] = "struct";
! 1293: first = 0;
! 1294: }
! 1295: return (const char**)str_mapping;
! 1296: }
! 1297: /* }}} */
! 1298:
! 1299: /* map an xmlrpc type to a string */
! 1300: const char* xmlrpc_type_as_str(XMLRPC_VALUE_TYPE type, XMLRPC_VECTOR_TYPE vtype) /* {{{ */
! 1301: {
! 1302: const char** str_mapping = get_type_str_mapping();
! 1303:
! 1304: if (vtype == xmlrpc_vector_none) {
! 1305: return str_mapping[type];
! 1306: } else {
! 1307: return str_mapping[XMLRPC_TYPE_COUNT + vtype];
! 1308: }
! 1309: }
! 1310: /* }}} */
! 1311:
! 1312: /* map a string to an xmlrpc type */
! 1313: XMLRPC_VALUE_TYPE xmlrpc_str_as_type(const char* str) /* {{{ */
! 1314: {
! 1315: const char** str_mapping = get_type_str_mapping();
! 1316: int i;
! 1317:
! 1318: if (str) {
! 1319: for (i = 0; i < XMLRPC_TYPE_COUNT; i++) {
! 1320: if (!strcmp(str_mapping[i], str)) {
! 1321: return (XMLRPC_VALUE_TYPE) i;
! 1322: }
! 1323: }
! 1324: }
! 1325: return xmlrpc_none;
! 1326: }
! 1327: /* }}} */
! 1328:
! 1329: /* map a string to an xmlrpc vector type */
! 1330: XMLRPC_VECTOR_TYPE xmlrpc_str_as_vector_type(const char* str) /* {{{ */
! 1331: {
! 1332: const char** str_mapping = get_type_str_mapping();
! 1333: int i;
! 1334:
! 1335: if (str) {
! 1336: for (i = XMLRPC_TYPE_COUNT; i < TYPE_STR_MAP_SIZE; i++) {
! 1337: if (!strcmp(str_mapping[i], str)) {
! 1338: return (XMLRPC_VECTOR_TYPE) (i - XMLRPC_TYPE_COUNT);
! 1339: }
! 1340: }
! 1341: }
! 1342: return xmlrpc_none;
! 1343: }
! 1344: /* }}} */
! 1345:
! 1346: /* set a given value to a particular type.
! 1347: * note: this only works on strings, and only for date and base64,
! 1348: * which do not have native php types. black magic lies herein.
! 1349: */
! 1350: int set_zval_xmlrpc_type(zval* value, XMLRPC_VALUE_TYPE newtype) /* {{{ */
! 1351: {
! 1352: int bSuccess = FAILURE;
! 1353: TSRMLS_FETCH();
! 1354:
! 1355: /* we only really care about strings because they can represent
! 1356: * base64 and datetime. all other types have corresponding php types
! 1357: */
! 1358: if (Z_TYPE_P(value) == IS_STRING) {
! 1359: if (newtype == xmlrpc_base64 || newtype == xmlrpc_datetime) {
! 1360: const char* typestr = xmlrpc_type_as_str(newtype, xmlrpc_vector_none);
! 1361: zval* type;
! 1362:
! 1363: MAKE_STD_ZVAL(type);
! 1364:
! 1365: Z_TYPE_P(type) = IS_STRING;
! 1366: Z_STRVAL_P(type) = estrdup(typestr);
! 1367: Z_STRLEN_P(type) = strlen(typestr);
! 1368:
! 1369: if (newtype == xmlrpc_datetime) {
! 1370: XMLRPC_VALUE v = XMLRPC_CreateValueDateTime_ISO8601(NULL, value->value.str.val);
! 1371: if (v) {
! 1372: time_t timestamp = (time_t) php_parse_date((char *)XMLRPC_GetValueDateTime_ISO8601(v), NULL);
! 1373: if (timestamp != -1) {
! 1374: zval* ztimestamp;
! 1375:
! 1376: MAKE_STD_ZVAL(ztimestamp);
! 1377:
! 1378: ztimestamp->type = IS_LONG;
! 1379: ztimestamp->value.lval = timestamp;
! 1380:
! 1381: convert_to_object(value);
! 1382: if (SUCCESS == zend_hash_update(Z_OBJPROP_P(value), OBJECT_TYPE_ATTR, sizeof(OBJECT_TYPE_ATTR), (void *) &type, sizeof(zval *), NULL)) {
! 1383: bSuccess = zend_hash_update(Z_OBJPROP_P(value), OBJECT_VALUE_TS_ATTR, sizeof(OBJECT_VALUE_TS_ATTR), (void *) &ztimestamp, sizeof(zval *), NULL);
! 1384: }
! 1385: } else {
! 1386: zval_ptr_dtor(&type);
! 1387: }
! 1388: XMLRPC_CleanupValue(v);
! 1389: } else {
! 1390: zval_ptr_dtor(&type);
! 1391: }
! 1392: } else {
! 1393: convert_to_object(value);
! 1394: bSuccess = zend_hash_update(Z_OBJPROP_P(value), OBJECT_TYPE_ATTR, sizeof(OBJECT_TYPE_ATTR), (void *) &type, sizeof(zval *), NULL);
! 1395: }
! 1396: }
! 1397: }
! 1398:
! 1399: return bSuccess;
! 1400: }
! 1401: /* }}} */
! 1402:
! 1403: /* return xmlrpc type of a php value */
! 1404: XMLRPC_VALUE_TYPE get_zval_xmlrpc_type(zval* value, zval** newvalue) /* {{{ */
! 1405: {
! 1406: XMLRPC_VALUE_TYPE type = xmlrpc_none;
! 1407: TSRMLS_FETCH();
! 1408:
! 1409: if (value) {
! 1410: switch (Z_TYPE_P(value)) {
! 1411: case IS_NULL:
! 1412: type = xmlrpc_base64;
! 1413: break;
! 1414: #ifndef BOOL_AS_LONG
! 1415:
! 1416: /* Right thing to do, but it breaks some legacy code. */
! 1417: case IS_BOOL:
! 1418: type = xmlrpc_boolean;
! 1419: break;
! 1420: #else
! 1421: case IS_BOOL:
! 1422: #endif
! 1423: case IS_LONG:
! 1424: case IS_RESOURCE:
! 1425: type = xmlrpc_int;
! 1426: break;
! 1427: case IS_DOUBLE:
! 1428: type = xmlrpc_double;
! 1429: break;
! 1430: case IS_CONSTANT:
! 1431: type = xmlrpc_string;
! 1432: break;
! 1433: case IS_STRING:
! 1434: type = xmlrpc_string;
! 1435: break;
! 1436: case IS_ARRAY:
! 1437: case IS_CONSTANT_ARRAY:
! 1438: type = xmlrpc_vector;
! 1439: break;
! 1440: case IS_OBJECT:
! 1441: {
! 1442: zval** attr;
! 1443: type = xmlrpc_vector;
! 1444:
! 1445: if (zend_hash_find(Z_OBJPROP_P(value), OBJECT_TYPE_ATTR, sizeof(OBJECT_TYPE_ATTR), (void**) &attr) == SUCCESS) {
! 1446: if (Z_TYPE_PP(attr) == IS_STRING) {
! 1447: type = xmlrpc_str_as_type(Z_STRVAL_PP(attr));
! 1448: }
! 1449: }
! 1450: break;
! 1451: }
! 1452: }
! 1453:
! 1454: /* if requested, return an unmolested (magic removed) copy of the value */
! 1455: if (newvalue) {
! 1456: zval** val;
! 1457:
! 1458: if ((type == xmlrpc_base64 && Z_TYPE_P(value) != IS_NULL) || type == xmlrpc_datetime) {
! 1459: if (zend_hash_find(Z_OBJPROP_P(value), OBJECT_VALUE_ATTR, sizeof(OBJECT_VALUE_ATTR), (void**) &val) == SUCCESS) {
! 1460: *newvalue = *val;
! 1461: }
! 1462: } else {
! 1463: *newvalue = value;
! 1464: }
! 1465: }
! 1466: }
! 1467:
! 1468: return type;
! 1469: }
! 1470: /* }}} */
! 1471:
! 1472: /* {{{ proto bool xmlrpc_set_type(string value, string type)
! 1473: Sets xmlrpc type, base64 or datetime, for a PHP string value */
! 1474: PHP_FUNCTION(xmlrpc_set_type)
! 1475: {
! 1476: zval **arg;
! 1477: char *type;
! 1478: int type_len;
! 1479: XMLRPC_VALUE_TYPE vtype;
! 1480:
! 1481: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zs", &arg, &type, &type_len) == FAILURE) {
! 1482: return;
! 1483: }
! 1484:
! 1485: vtype = xmlrpc_str_as_type(type);
! 1486: if (vtype != xmlrpc_none) {
! 1487: if (set_zval_xmlrpc_type(*arg, vtype) == SUCCESS) {
! 1488: RETURN_TRUE;
! 1489: }
! 1490: } else {
! 1491: zend_error(E_WARNING,"invalid type '%s' passed to xmlrpc_set_type()", type);
! 1492: }
! 1493: RETURN_FALSE;
! 1494: }
! 1495: /* }}} */
! 1496:
! 1497: /* {{{ proto string xmlrpc_get_type(mixed value)
! 1498: Gets xmlrpc type for a PHP value. Especially useful for base64 and datetime strings */
! 1499: PHP_FUNCTION(xmlrpc_get_type)
! 1500: {
! 1501: zval **arg;
! 1502: XMLRPC_VALUE_TYPE type;
! 1503: XMLRPC_VECTOR_TYPE vtype = xmlrpc_vector_none;
! 1504:
! 1505: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg) == FAILURE) {
! 1506: return;
! 1507: }
! 1508:
! 1509: type = get_zval_xmlrpc_type(*arg, 0);
! 1510: if (type == xmlrpc_vector) {
! 1511: vtype = determine_vector_type((Z_TYPE_PP(arg) == IS_OBJECT) ? Z_OBJPROP_PP(arg) : Z_ARRVAL_PP(arg));
! 1512: }
! 1513:
! 1514: RETURN_STRING((char*) xmlrpc_type_as_str(type, vtype), 1);
! 1515: }
! 1516: /* }}} */
! 1517:
! 1518: /* {{{ proto bool xmlrpc_is_fault(array)
! 1519: Determines if an array value represents an XMLRPC fault. */
! 1520: PHP_FUNCTION(xmlrpc_is_fault)
! 1521: {
! 1522: zval *arg, **val;
! 1523:
! 1524: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &arg) == FAILURE) {
! 1525: return;
! 1526: }
! 1527:
! 1528: /* The "correct" way to do this would be to call the xmlrpc
! 1529: * library XMLRPC_ValueIsFault() func. However, doing that
! 1530: * would require us to create an xmlrpc value from the php
! 1531: * array, which is rather expensive, especially if it was
! 1532: * a big array. Thus, we resort to this not so clever hackery.
! 1533: */
! 1534: if (zend_hash_find(Z_ARRVAL_P(arg), FAULT_CODE, FAULT_CODE_LEN + 1, (void**) &val) == SUCCESS &&
! 1535: zend_hash_find(Z_ARRVAL_P(arg), FAULT_STRING, FAULT_STRING_LEN + 1, (void**) &val) == SUCCESS) {
! 1536: RETURN_TRUE;
! 1537: }
! 1538:
! 1539: RETURN_FALSE;
! 1540: }
! 1541: /* }}} */
! 1542:
! 1543: /*
! 1544: * Local variables:
! 1545: * tab-width: 4
! 1546: * c-basic-offset: 4
! 1547: * End:
! 1548: */
! 1549:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>