remove simplejson dependency
[plcapi.git] / php / xmlrpc / xmlrpc-epi-php.c
index befaec8..c2dc4e0 100644 (file)
@@ -51,8 +51,6 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: xmlrpc-epi-php.c,v 1.37 2004/01/08 08:17:47 andi Exp $ */
-
 /**********************************************************************
 * BUGS:                                                               *
 *  - when calling a php user function, there appears to be no way to  *
 
 #define PHP_EXT_VERSION "0.51"
 
+/* ====================
+ * Thierry - Dec. 17 2009 
+ * patch for php - bug first triggered on f12 with php-5.3
+ * http://pecl.php.net/bugs/bug.php?id=14369
+ * http://remi.fedorapeople.org/ncurses-1.0.0-php53.patch
+ * I'm taking out the 'static' stuff as after pre-processing it appears to be part of the macro expansion already
+ */
+#if ZEND_MODULE_API_NO >= 20071006
+// No more defined with PHP 5.3.0
+       ZEND_BEGIN_ARG_INFO(first_arg_force_ref, 0)
+               ZEND_ARG_PASS_INFO(1)
+       ZEND_END_ARG_INFO();
+
+       ZEND_BEGIN_ARG_INFO(second_arg_force_ref, 0)
+               ZEND_ARG_PASS_INFO(0)
+               ZEND_ARG_PASS_INFO(1)
+       ZEND_END_ARG_INFO();
+#endif
+/* ==================== end patch */
+
+/* ====================
+ * Thierry - Jan. 30 2013 
+ * patch for php - issues first triggered on f18 with php-5.4
+ * https://bugs.php.net/bug.php?id=60016 
+ * https://bugs.php.net/bug.php?id=60016 
+ */
+#if ZEND_MODULE_API_NO >= 20100525
+// No more defined with PHP 5.4
+#define function_entry zend_function_entry
+#define pval zval
+#endif
+/* ==================== end patch */
+
+/* ====================
+ * Thierry - Jan. 2 2015 
+ * patch for php - issues first triggered on f21 with php-5.6
+ * somebody somehow seems to have undefined 
+ * the IS_CONSTANT_ARRAY constant
+ * 
+ * however I'd rather not change the code that runs 
+ * on older releases, so see for the ugly ifdef below
+ * 
+/* ==================== end patch */
+
+
+/* ========== additional notes
+ * in the process, I've also come across the following resources that might help 
+ * if/when zend_get_parameters_ex gets deprecated (only generates warnings for now)
+ *
+ * http://developers.evrsoft.com/docs/php/zend.arguments.deprecated-retrieval.shtml
+ * explains how the old (our) stuff works
+ *
+ * http://www.hospedajeydominios.com/mambo/documentacion-manual_php-pagina-zend_arguments_retrieval.html
+ * gives info on the new scheme
+ *
+ * I'm taking tha risk as the changes seem to mean major surgery ...
+ */
+
 /* You should tweak config.m4 so this symbol (or some else suitable)
        gets defined.  */
 
@@ -118,6 +174,15 @@ ZEND_GET_MODULE(xmlrpc)
 # endif
 #endif
 
+PHP_INI_BEGIN()
+STD_PHP_INI_BOOLEAN("xmlrpc.allow_null", "0", PHP_INI_ALL, OnUpdateBool, allow_null, zend_xmlrpc_globals, xmlrpc_globals)
+PHP_INI_END()
+
+static void php_xmlrpc_init_globals(zend_xmlrpc_globals *xmlrpc_globals)
+{
+       memset(xmlrpc_globals, 0, sizeof(zend_xmlrpc_globals));
+}
+
 /*******************************
 * local structures and defines *
 *******************************/
@@ -134,6 +199,7 @@ typedef struct _xmlrpc_server_data {
 typedef struct _php_output_options {
        int b_php_out;
        int b_auto_version;
+       int b_allow_null;
        STRUCT_XMLRPC_REQUEST_OUTPUT_OPTIONS xmlrpc_out;
 } php_output_options;
 
@@ -153,6 +219,9 @@ typedef struct _xmlrpc_callback_data {
 #define OUTPUT_TYPE_VALUE_PHP "php"
 #define OUTPUT_TYPE_VALUE_XML "xml"
 
+#define ALLOW_NULL_KEY     "allow_null"
+#define ALLOW_NULL_KEY_LEN (sizeof(ALLOW_NULL_KEY) - 1)
+
 #define VERBOSITY_KEY                  "verbosity"
 #define VERBOSITY_KEY_LEN              (sizeof(VERBOSITY_KEY) - 1)
 #define VERBOSITY_VALUE_NO_WHITE_SPACE "no_white_space"
@@ -191,7 +260,7 @@ typedef struct _xmlrpc_callback_data {
 /***********************
 * forward declarations *
 ***********************/
-XMLRPC_VALUE_TYPE get_zval_xmlrpc_type(zval* value, zval** newvalue);
+XMLRPC_VALUE_TYPE get_zval_xmlrpc_type(php_output_options* out, zval* value, zval** newvalue);
 static void php_xmlrpc_introspection_callback(XMLRPC_SERVER server, void* data);
 int sset_zval_xmlrpc_type(zval* value, XMLRPC_VALUE_TYPE type);
 zval* decode_request_worker(zval* xml_in, zval* encoding_in, zval* method_name_out);
@@ -231,6 +300,10 @@ static void xmlrpc_server_destructor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
 /* module init */
 PHP_MINIT_FUNCTION(xmlrpc)
 {
+       ZEND_INIT_MODULE_GLOBALS(xmlrpc, php_xmlrpc_init_globals, NULL);
+
+       REGISTER_INI_ENTRIES();
+
        le_xmlrpc_server = zend_register_list_destructors_ex(xmlrpc_server_destructor, NULL, "xmlrpc server", module_number);
 
        return SUCCESS;
@@ -320,11 +393,14 @@ static int add_zval(zval* list, const char* id, zval** val)
  * and determine whether to return data as xml or php vars */
 static void set_output_options(php_output_options* options, zval* output_opts)
 {
+       XMLRPCLS_FETCH();
+
        if (options) {
 
                /* defaults */
                options->b_php_out = 0;
                options->b_auto_version = 1;
+               options->b_allow_null = 0;
                options->xmlrpc_out.version = xmlrpc_version_1_0;
                options->xmlrpc_out.xml_elem_opts.encoding = ENCODING_DEFAULT;
                options->xmlrpc_out.xml_elem_opts.verbosity = xml_elem_pretty;
@@ -333,6 +409,17 @@ static void set_output_options(php_output_options* options, zval* output_opts)
                if (output_opts && Z_TYPE_P(output_opts) == IS_ARRAY) {
                        zval** val;
 
+                       /* marshal NULL */
+                       if (zend_hash_find(Z_ARRVAL_P(output_opts), ALLOW_NULL_KEY, ALLOW_NULL_KEY_LEN + 1, (void**) &val) == SUCCESS) {
+                               if (Z_TYPE_PP(val) == IS_BOOL) {
+                                       if (Z_LVAL_PP(val)) {
+                                               options->b_allow_null = 1;
+                                       } else {
+                                               options->b_allow_null = 0;
+                                       }
+                               }
+                       }
+
                        /* type of output (xml/php) */
                        if (zend_hash_find(Z_ARRVAL_P(output_opts), OUTPUT_TYPE_KEY, OUTPUT_TYPE_KEY_LEN + 1, (void**) &val) == SUCCESS) {
                                if (Z_TYPE_PP(val) == IS_STRING) {
@@ -478,22 +565,20 @@ static XMLRPC_VECTOR_TYPE determine_vector_type (HashTable *ht)
 }
 
 /* recursively convert php values into xmlrpc values */
-static XMLRPC_VALUE PHP_to_XMLRPC_worker (const char* key, zval* in_val, int depth)
+static XMLRPC_VALUE PHP_to_XMLRPC_worker (php_output_options* out, const char* key, zval* in_val, int depth)
 {
    XMLRPC_VALUE xReturn = NULL;
    if(in_val) {
       zval* val = NULL;
-      XMLRPC_VALUE_TYPE type = get_zval_xmlrpc_type(in_val, &val);
+      XMLRPC_VALUE_TYPE type = get_zval_xmlrpc_type(out, in_val, &val);
       if(val) {
          switch(type) {
+            case xmlrpc_nil:
+               xReturn = XMLRPC_CreateValueEmpty();
+               XMLRPC_SetValueID(xReturn, key, 0);
+               break;
             case xmlrpc_base64:
-               if(Z_TYPE_P(val) == IS_NULL) {
-                  xReturn = XMLRPC_CreateValueEmpty();
-                                               XMLRPC_SetValueID(xReturn, key, 0);
-               }
-               else {
-                  xReturn = XMLRPC_CreateValueBase64(key, Z_STRVAL_P(val), Z_STRLEN_P(val));
-               }
+               xReturn = XMLRPC_CreateValueBase64(key, Z_STRVAL_P(val), Z_STRLEN_P(val));
                break;
             case xmlrpc_datetime:
                convert_to_string(val);
@@ -530,7 +615,7 @@ static XMLRPC_VALUE PHP_to_XMLRPC_worker (const char* key, zval* in_val, int dep
                      int res = my_zend_hash_get_current_key(Z_ARRVAL_P(val), &my_key, &num_index);
                      if(res == HASH_KEY_IS_LONG) {
                         if(zend_hash_get_current_data(Z_ARRVAL_P(val), (void**)&pIter) == SUCCESS) {
-                           XMLRPC_AddValueToVector(xReturn, PHP_to_XMLRPC_worker(0, *pIter, depth++));
+                           XMLRPC_AddValueToVector(xReturn, PHP_to_XMLRPC_worker(out, 0, *pIter, depth++));
                         }
                      }
                      else if(res == HASH_KEY_NON_EXISTANT) {
@@ -538,7 +623,7 @@ static XMLRPC_VALUE PHP_to_XMLRPC_worker (const char* key, zval* in_val, int dep
                      }
                      else if(res == HASH_KEY_IS_STRING) {
                         if(zend_hash_get_current_data(Z_ARRVAL_P(val), (void**)&pIter) == SUCCESS) {
-                           XMLRPC_AddValueToVector(xReturn, PHP_to_XMLRPC_worker(my_key, *pIter, depth++));
+                           XMLRPC_AddValueToVector(xReturn, PHP_to_XMLRPC_worker(out, my_key, *pIter, depth++));
                         }
                      }
 
@@ -554,9 +639,9 @@ static XMLRPC_VALUE PHP_to_XMLRPC_worker (const char* key, zval* in_val, int dep
    return xReturn;
 }
 
-static XMLRPC_VALUE PHP_to_XMLRPC(zval* root_val)
+static XMLRPC_VALUE PHP_to_XMLRPC(php_output_options* out, zval* root_val)
 {
-   return PHP_to_XMLRPC_worker(NULL, root_val, 0);
+   return PHP_to_XMLRPC_worker(out, NULL, root_val, 0);
 }
 
 /* recursively convert xmlrpc values into php values */
@@ -572,6 +657,7 @@ static zval* XMLRPC_to_PHP(XMLRPC_VALUE el)
 
       switch(type) {
          case xmlrpc_empty:
+         case xmlrpc_nil:
             Z_TYPE_P(elem) = IS_NULL;
             break;
          case xmlrpc_string:
@@ -656,7 +742,7 @@ PHP_FUNCTION(xmlrpc_encode_request)
                                XMLRPC_RequestSetRequestType(xRequest, xmlrpc_request_call);
                        }
                        if (Z_TYPE_PP(vals) != IS_NULL) {
-                               XMLRPC_RequestSetData(xRequest, PHP_to_XMLRPC(*vals));
+                               XMLRPC_RequestSetData(xRequest, PHP_to_XMLRPC(&out, *vals));
                        }
 
                        outBuf = XMLRPC_REQUEST_ToXML(xRequest, 0);
@@ -684,7 +770,7 @@ PHP_FUNCTION(xmlrpc_encode)
 
        if( return_value_used ) {
                /* convert native php type to xmlrpc type */
-               xOut = PHP_to_XMLRPC(*arg1);
+               xOut = PHP_to_XMLRPC(NULL, *arg1);
 
                /* generate raw xml from xmlrpc data */
                outBuf = XMLRPC_VALUE_ToXML(xOut, 0);
@@ -1086,7 +1172,7 @@ PHP_FUNCTION(xmlrpc_server_call_method)
                                FREE_ZVAL(data.return_data);
                                data.return_data = XMLRPC_to_PHP(xAnswer);
                        } else if(data.php_executed && !out.b_php_out) {
-                               xAnswer = PHP_to_XMLRPC(data.return_data);
+                               xAnswer = PHP_to_XMLRPC(&out, data.return_data);
                        }
 
                        /* should we return data as xml? */
@@ -1155,7 +1241,7 @@ PHP_FUNCTION(xmlrpc_server_add_introspection_data)
        server = zend_list_find(Z_LVAL_PP(handle), &type);
 
        if (type == le_xmlrpc_server) {
-               XMLRPC_VALUE xDesc = PHP_to_XMLRPC(*desc);
+               XMLRPC_VALUE xDesc = PHP_to_XMLRPC(NULL, *desc);
                if (xDesc) {
                        int retval = XMLRPC_ServerAddIntrospectionData(server->server_ptr, xDesc);
                        XMLRPC_CleanupValue(xDesc);
@@ -1211,7 +1297,7 @@ PHP_FUNCTION(xmlrpc_parse_method_descriptions)
 * type data *
 ************/
 
-#define XMLRPC_TYPE_COUNT 9
+#define XMLRPC_TYPE_COUNT 10
 #define XMLRPC_VECTOR_TYPE_COUNT 4
 #define TYPE_STR_MAP_SIZE (XMLRPC_TYPE_COUNT + XMLRPC_VECTOR_TYPE_COUNT)
 
@@ -1224,6 +1310,7 @@ static const char** get_type_str_mapping(void)
       /* warning. do not add/delete without changing size define */
       str_mapping[xmlrpc_none]     = "none";
       str_mapping[xmlrpc_empty]    = "empty";
+      str_mapping[xmlrpc_nil]      = "nil";
       str_mapping[xmlrpc_base64]   = "base64";
       str_mapping[xmlrpc_boolean]  = "boolean";
       str_mapping[xmlrpc_datetime] = "datetime";
@@ -1339,15 +1426,20 @@ int set_zval_xmlrpc_type(zval* value, XMLRPC_VALUE_TYPE newtype)
 }
 
 /* return xmlrpc type of a php value */
-XMLRPC_VALUE_TYPE get_zval_xmlrpc_type(zval* value, zval** newvalue)
+XMLRPC_VALUE_TYPE get_zval_xmlrpc_type(php_output_options* out, zval* value, zval** newvalue)
 {
    XMLRPC_VALUE_TYPE type = xmlrpc_none;
    TSRMLS_FETCH();
+   XMLRPCLS_FETCH();
 
    if (value) {
       switch (Z_TYPE_P(value)) {
          case IS_NULL:
-            type = xmlrpc_base64;
+            if (XMLRPCG(allow_null) || (out && out->b_allow_null)) {
+               type = xmlrpc_nil;
+            } else {
+               type = xmlrpc_string;
+            }
             break;
 #ifndef BOOL_AS_LONG
 
@@ -1372,7 +1464,10 @@ XMLRPC_VALUE_TYPE get_zval_xmlrpc_type(zval* value, zval** newvalue)
             type = xmlrpc_string;
             break;
          case IS_ARRAY:
+/* jan. 2 2015 - see note in file header */
+#ifdef IS_CONSTANT_ARRAY
          case IS_CONSTANT_ARRAY:
+#endif
             type = xmlrpc_vector;
             break;
          case IS_OBJECT:
@@ -1408,7 +1503,7 @@ XMLRPC_VALUE_TYPE get_zval_xmlrpc_type(zval* value, zval** newvalue)
 
 
 /* {{{ proto bool xmlrpc_set_type(string value, string type)
-   Sets xmlrpc type, base64 or datetime, for a PHP string value */
+   Sets xmlrpc type, base64 or datetime or nil, for a PHP string value */
 PHP_FUNCTION(xmlrpc_set_type)
 {
        zval **arg, **type;
@@ -1443,7 +1538,7 @@ PHP_FUNCTION(xmlrpc_get_type)
                WRONG_PARAM_COUNT;
        }
 
-       type = get_zval_xmlrpc_type(*arg, 0);
+       type = get_zval_xmlrpc_type(NULL, *arg, 0);
        if (type == xmlrpc_vector) {
                vtype = determine_vector_type(Z_ARRVAL_PP(arg));
        }