/* +----------------------------------------------------------------------+ | Copyright (c) The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: | | Israel Ekpo | | Omar Shaban | +----------------------------------------------------------------------+ */ #include "php_solr.h" ZEND_EXTERN_MODULE_GLOBALS(json) /** ************************************************************************ **/ /** FUNCTIONS FOR DECLARING CONSTANTS **/ /** ************************************************************************ **/ /* {{{ void solr_extension_register_constants(int type, int module_number) */ PHP_SOLR_API void solr_extension_register_constants(int type, int module_number) { REGISTER_LONG_CONSTANT("SOLR_MAJOR_VERSION", PHP_SOLR_MAJOR_VERSION, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SOLR_MINOR_VERSION", PHP_SOLR_MINOR_VERSION, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SOLR_PATCH_VERSION", PHP_SOLR_PATCH_VERSION, CONST_CS | CONST_PERSISTENT); REGISTER_STRING_CONSTANT("SOLR_EXTENSION_VERSION", PHP_SOLR_DOTTED_VERSION, CONST_CS | CONST_PERSISTENT); } /* }}} */ /* {{{ void solr_document_register_class_constants(zend_class_entry * ce) */ PHP_SOLR_API void solr_document_register_class_constants(zend_class_entry *ce) { zend_declare_class_constant_long(ce, "SORT_DEFAULT", sizeof("SORT_DEFAULT")-1, SOLR_SORT_ASC); zend_declare_class_constant_long(ce, "SORT_ASC", sizeof("SORT_ASC")-1, SOLR_SORT_ASC); zend_declare_class_constant_long(ce, "SORT_DESC", sizeof("SORT_DESC")-1, SOLR_SORT_DESC); zend_declare_class_constant_long(ce, "SORT_FIELD_NAME", sizeof("SORT_FIELD_NAME")-1, SOLR_SORT_FIELD_NAME); zend_declare_class_constant_long(ce, "SORT_FIELD_VALUE_COUNT", sizeof("SORT_FIELD_VALUE_COUNT")-1, SOLR_SORT_FIELD_VALUE_COUNT); zend_declare_class_constant_long(ce, "SORT_FIELD_BOOST_VALUE", sizeof("SORT_FIELD_BOOST_VALUE")-1, SOLR_SORT_FIELD_BOOST_VALUE); } /* }}} */ PHP_SOLR_API void solr_input_document_register_class_constants(zend_class_entry *ce) { solr_document_register_class_constants(ce); zend_declare_class_constant_long(ce, "UPDATE_MODIFIER_ADD", sizeof("UPDATE_MODIFIER_ADD")-1, SOLR_FIELD_VALUE_MOD_ADD); zend_declare_class_constant_long(ce, "UPDATE_MODIFIER_SET", sizeof("UPDATE_MODIFIER_SET")-1, SOLR_FIELD_VALUE_MOD_SET); zend_declare_class_constant_long(ce, "UPDATE_MODIFIER_INC", sizeof("UPDATE_MODIFIER_INC")-1, SOLR_FIELD_VALUE_MOD_INC); zend_declare_class_constant_long(ce, "UPDATE_MODIFIER_REMOVE", sizeof("UPDATE_MODIFIER_REMOVE")-1, SOLR_FIELD_VALUE_MOD_REMOVE); zend_declare_class_constant_long(ce, "UPDATE_MODIFIER_REMOVEREGEX", sizeof("UPDATE_MODIFIER_REMOVEREGEX")-1, SOLR_FIELD_VALUE_MOD_REMOVEREGEX); zend_declare_class_constant_long(ce, "VERSION_ASSERT_NONE", sizeof("VERSION_ASSERT_NONE")-1, SOLR_VERSION_ASSERT_NONE); zend_declare_class_constant_long(ce, "VERSION_ASSERT_EXISTS", sizeof("VERSION_ASSERT_EXISTS")-1, SOLR_VERSION_ASSERT_EXISTS); zend_declare_class_constant_long(ce, "VERSION_ASSERT_NOT_EXISTS", sizeof("VERSION_ASSERT_NOT_EXISTS")-1, SOLR_VERSION_ASSERT_NOT_EXISTS); } /* {{{ void solr_collapse_function_register_class_constants(zend_class_entry * ce) */ PHP_SOLR_API void solr_collapse_function_register_class_constants(zend_class_entry *ce) { zend_declare_class_constant_string(ce, "NULLPOLICY_IGNORE", sizeof("NULLPOLICY_IGNORE")-1, "ignore"); zend_declare_class_constant_string(ce, "NULLPOLICY_EXPAND", sizeof("NULLPOLICY_EXPAND")-1, "expand"); zend_declare_class_constant_string(ce, "NULLPOLICY_COLLAPSE", sizeof("NULLPOLICY_COLLAPSE")-1, "collapse"); } /* }}} */ /* {{{ void solr_client_register_class_constants(zend_class_entry *ce) */ PHP_SOLR_API void solr_client_register_class_constants(zend_class_entry *ce) { zend_declare_class_constant_long(ce, "SEARCH_SERVLET_TYPE", sizeof("SEARCH_SERVLET_TYPE")-1, SOLR_SERVLET_TYPE_SEARCH); zend_declare_class_constant_long(ce, "UPDATE_SERVLET_TYPE", sizeof("UPDATE_SERVLET_TYPE")-1, SOLR_SERVLET_TYPE_UPDATE); zend_declare_class_constant_long(ce, "THREADS_SERVLET_TYPE", sizeof("THREADS_SERVLET_TYPE")-1, SOLR_SERVLET_TYPE_THREADS); zend_declare_class_constant_long(ce, "PING_SERVLET_TYPE", sizeof("PING_SERVLET_TYPE")-1, SOLR_SERVLET_TYPE_PING); zend_declare_class_constant_long(ce, "TERMS_SERVLET_TYPE", sizeof("TERMS_SERVLET_TYPE")-1, SOLR_SERVLET_TYPE_TERMS); zend_declare_class_constant_long(ce, "SYSTEM_SERVLET_TYPE", sizeof("SYSTEM_SERVLET_TYPE")-1, SOLR_SERVLET_TYPE_SYSTEM); zend_declare_class_constant_string(ce, "DEFAULT_SEARCH_SERVLET", sizeof("DEFAULT_SEARCH_SERVLET")-1, SOLR_DEFAULT_SEARCH_SERVLET); zend_declare_class_constant_string(ce, "DEFAULT_UPDATE_SERVLET", sizeof("DEFAULT_UPDATE_SERVLET")-1, SOLR_DEFAULT_UPDATE_SERVLET); zend_declare_class_constant_string(ce, "DEFAULT_THREADS_SERVLET", sizeof("DEFAULT_THREADS_SERVLET")-1, SOLR_DEFAULT_THREADS_SERVLET); zend_declare_class_constant_string(ce, "DEFAULT_PING_SERVLET", sizeof("DEFAULT_PING_SERVLET")-1, SOLR_DEFAULT_PING_SERVLET); zend_declare_class_constant_string(ce, "DEFAULT_TERMS_SERVLET", sizeof("DEFAULT_TERMS_SERVLET")-1, SOLR_DEFAULT_TERMS_SERVLET); zend_declare_class_constant_string(ce, "DEFAULT_SYSTEM_SERVLET", sizeof("DEFAULT_SYSTEM_SERVLET")-1, SOLR_DEFAULT_SYSTEM_SERVLET); } /* }}} */ /* {{{ void solr_response_register_class_properties(zend_class_entry *ce) */ PHP_SOLR_API void solr_response_register_class_properties(zend_class_entry *ce) { zend_declare_property_long(ce, "http_status", sizeof("http_status")-1, 0L, ZEND_ACC_PROTECTED); zend_declare_property_long(ce, "parser_mode", sizeof("parser_mode")-1, 0L, ZEND_ACC_PROTECTED); zend_declare_property_bool(ce, "success", sizeof("success")-1, 0L, ZEND_ACC_PROTECTED); zend_declare_property_string(ce, "response_writer", sizeof("response_writer")-1, SOLR_SPACE_STRING, ZEND_ACC_PROTECTED); zend_declare_property_string(ce, "http_status_message", sizeof("http_status_message")-1, SOLR_SPACE_STRING, ZEND_ACC_PROTECTED); zend_declare_property_string(ce, "http_request_url", sizeof("http_request_url")-1, SOLR_SPACE_STRING, ZEND_ACC_PROTECTED); zend_declare_property_string(ce, "http_raw_request_headers", sizeof("http_raw_request_headers")-1, SOLR_SPACE_STRING, ZEND_ACC_PROTECTED); zend_declare_property_string(ce, "http_raw_request", sizeof("http_raw_request")-1, SOLR_SPACE_STRING, ZEND_ACC_PROTECTED); zend_declare_property_string(ce, "http_raw_response_headers", sizeof("http_raw_response_headers")-1, SOLR_SPACE_STRING, ZEND_ACC_PROTECTED); zend_declare_property_string(ce, "http_raw_response", sizeof("http_raw_response")-1, SOLR_SPACE_STRING, ZEND_ACC_PROTECTED); zend_declare_property_string(ce, "http_digested_response", sizeof("http_digested_response")-1, SOLR_SPACE_STRING, ZEND_ACC_PROTECTED); } /* }}} */ /* {{{ void solr_exception_register_class_properties(zend_class_entry *ce) */ PHP_SOLR_API void solr_exception_register_class_properties(zend_class_entry *ce) { zend_declare_property_long(ce, SOLR_SOURCELINE_NO_PROPERTY_NAME, sizeof(SOLR_SOURCELINE_NO_PROPERTY_NAME)-1, __LINE__, ZEND_ACC_PROTECTED); zend_declare_property_string(ce, SOLR_SOURCEFILE_PROPERTY_NAME, sizeof(SOLR_SOURCEFILE_PROPERTY_NAME)-1, __FILE__, ZEND_ACC_PROTECTED); zend_declare_property_string(ce, SOLR_ZIFNAME_PROPERTY_NAME, sizeof(SOLR_ZIFNAME_PROPERTY_NAME)-1, (char *) __func__, ZEND_ACC_PROTECTED); } /* }}} */ /* {{{ void solr_response_register_class_constants(zend_class_entry *ce) */ PHP_SOLR_API void solr_response_register_class_constants(zend_class_entry *ce) { zend_declare_class_constant_long(ce, "PARSE_SOLR_OBJ", sizeof("PARSE_SOLR_OBJ")-1, 0L); zend_declare_class_constant_long(ce, "PARSE_SOLR_DOC", sizeof("PARSE_SOLR_DOC")-1, 1L); } /* }}} */ /* {{{ void solr_query_register_class_constants(zend_class_entry *ce) */ PHP_SOLR_API void solr_query_register_class_constants(zend_class_entry *ce) { zend_declare_class_constant_long(ce, "ORDER_ASC", sizeof("ORDER_ASC")-1, SOLR_SORT_DIR_ASC); zend_declare_class_constant_long(ce, "ORDER_DESC", sizeof("ORDER_DESC")-1, SOLR_SORT_DIR_DESC); zend_declare_class_constant_long(ce, "FACET_SORT_INDEX", sizeof("FACET_SORT_INDEX")-1, 0L); zend_declare_class_constant_long(ce, "FACET_SORT_COUNT", sizeof("FACET_SORT_COUNT")-1, 1L); zend_declare_class_constant_long(ce, "TERMS_SORT_INDEX", sizeof("TERMS_SORT_INDEX")-1, 0L); zend_declare_class_constant_long(ce, "TERMS_SORT_COUNT", sizeof("TERMS_SORT_COUNT")-1, 1L); } /* }}} */ PHP_SOLR_API void solr_extract_register_class_constants(zend_class_entry *ce) { zend_declare_class_constant_string(ce, "CAPTURE_ELEMENTS", sizeof("CAPTURE_ELEMENTS")-1, "capture"); zend_declare_class_constant_string(ce, "CAPTURE_ATTRIBUTES", sizeof("CAPTURE_ATTRIBUTES")-1, "captureAttr"); zend_declare_class_constant_string(ce, "COMMIT_WITHIN", sizeof("COMMIT_WITHIN")-1, "commitWithin"); zend_declare_class_constant_string(ce, "DATE_FORMATS", sizeof("DATE_FORMATS")-1, "date.formats"); zend_declare_class_constant_string(ce, "DEFAULT_FIELD", sizeof("DEFAULT_FIELD")-1, "defaultField"); zend_declare_class_constant_string(ce, "EXTRACT_ONLY", sizeof("EXTRACT_ONLY")-1, "extractOnly"); zend_declare_class_constant_string(ce, "EXTRACT_FORMAT", sizeof("EXTRACT_FORMAT")-1,"extractFormat"); zend_declare_class_constant_string(ce, "IGNORE_TIKA_EXCEPTION", sizeof("IGNORE_TIKA_EXCEPTION")-1, "ignoreTikaException"); zend_declare_class_constant_string(ce, "LITERALS_OVERRIDE", sizeof("LITERALS_OVERRIDE")-1, "literalsOverride"); zend_declare_class_constant_string(ce, "LOWERNAMES", sizeof("LOWERNAMES")-1, "lowernames"); zend_declare_class_constant_string(ce, "MULTIPART_UPLOAD_LIMIT", sizeof("MULTIPART_UPLOAD_LIMIT")-1, "multipartUploadLimitInKB"); zend_declare_class_constant_string(ce, "PASSWORD_MAP_FILE", sizeof("PASSWORD_MAP_FILE")-1, "passwordsFile"); zend_declare_class_constant_string(ce, "RESOURCE_NAME", sizeof("RESOURCE_NAME")-1, "resource.name"); zend_declare_class_constant_string(ce, "RESOURCE_PASSWORD", sizeof("RESOURCE_PASSWORD")-1, "resource.password"); zend_declare_class_constant_string(ce, "TIKE_CONFIG", sizeof("TIKE_CONFIG")-1, "tika.config"); zend_declare_class_constant_string(ce, "UNKNOWN_FIELD_PREFIX", sizeof("UNKNOWN_FIELD_PREFIX")-1, "uprefix"); zend_declare_class_constant_string(ce, "XPATH_EXPRESSION", sizeof("XPATH_EXPRESSION")-1, "xpath"); zend_declare_class_constant_string(ce, "FIELD_MAPPING_PREFIX", sizeof("FIELD_MAPPING_PREFIX")-1, "fmap."); zend_declare_class_constant_string(ce, "FIELD_BOOST_PREFIX", sizeof("FIELD_BOOST_PREFIX")-1, "boost."); zend_declare_class_constant_string(ce, "LITERALS_PREFIX", sizeof("LITERALS_PREFIX")-1, "literal."); } /** ************************************************************************ **/ /** UTILITY FUNCTIONS **/ /** ************************************************************************ **/ /* {{{ int solr_hashtable_get_new_index(HashTable *ht) Retrieves a unique index for this HashTable */ PHP_SOLR_API int solr_hashtable_get_new_index(HashTable *ht) { int new_index = SOLR_GET_RANDOM_NUMBER(); /* If the key already exists in the HashTable, create another one. */ while(zend_hash_index_exists(ht, new_index)) { new_index = SOLR_GET_RANDOM_NUMBER(); } return new_index; } /* }}} */ /* {{{ static inline int solr_fetch_document_entry(zval *objptr, solr_document_t **doc_entry) Retrieves a Document from the HashTable */ #if PHP_VERSION_ID < 80000 PHP_SOLR_API int solr_fetch_document_entry(zval *objptr, solr_document_t **doc_entry) { zval *rv = NULL; zval *id = zend_read_property(Z_OBJCE_P(objptr), objptr, SOLR_INDEX_PROPERTY_NAME, sizeof(SOLR_INDEX_PROPERTY_NAME) - 1, 1, rv); #else PHP_SOLR_API int solr_fetch_document_entry(zend_object *objptr, solr_document_t **doc_entry) { zval *rv = NULL; zval *id = zend_read_property(objptr->ce, objptr, SOLR_INDEX_PROPERTY_NAME, sizeof(SOLR_INDEX_PROPERTY_NAME) - 1, 1, rv); #endif /* Retrieving the value of the document index from the zval */ long int document_index = Z_LVAL_P(id); *doc_entry = NULL; /* Retrieve the doc_entry from the HashTable */ if ((*doc_entry = (solr_document_t *)zend_hash_index_find_ptr(SOLR_GLOBAL(documents), document_index)) == NULL) { php_error_docref(NULL, E_WARNING, "Invalid Document Index %ld. HashTable index does not exist.", document_index); php_error_docref(NULL, E_WARNING, SOLR_ERROR_1008_MSG, SOLR_FILE_LINE_FUNC); return FAILURE; } return SUCCESS; } /* }}} */ /* {{{ PHP_SOLR_API int solr_fetch_client_entry(zval *objptr, solr_client_t **solr_client) */ PHP_SOLR_API int solr_fetch_client_entry(zval *objptr, solr_client_t **solr_client) { zval rv; zval *id = zend_read_property(solr_ce_SolrClient, OBJ_FOR_PROP(objptr), SOLR_INDEX_PROPERTY_NAME, sizeof(SOLR_INDEX_PROPERTY_NAME) - 1, 1, &rv); /* Retrieving the value of the client index from the zval */ long int client_index = Z_LVAL_P(id); *solr_client = NULL; /* Retrieve the doc_entry from the HashTable */ if ((*solr_client = zend_hash_index_find_ptr(SOLR_GLOBAL(clients), client_index)) == NULL) { php_error_docref(NULL, E_WARNING, "Invalid SolrClient Index %ld. HashTable index does not exist.", client_index); php_error_docref(NULL, E_WARNING, SOLR_ERROR_1008_MSG, SOLR_FILE_LINE_FUNC); return FAILURE; } return SUCCESS; } /* }}} */ /* {{{ PHP_SOLR_API int solr_fetch_params_entry(zval *objptr, solr_params_t **solr_params) */ PHP_SOLR_API int solr_fetch_params_entry(zval *objptr, solr_params_t **solr_params) { zval rv; zval *id = zend_read_property(Z_OBJCE_P(objptr), OBJ_FOR_PROP(objptr), SOLR_INDEX_PROPERTY_NAME, sizeof(SOLR_INDEX_PROPERTY_NAME) - 1, 1, &rv); long int params_index = Z_LVAL_P(id); *solr_params = NULL; if ((*solr_params = zend_hash_index_find_ptr(SOLR_GLOBAL(params), params_index)) == NULL) { php_error_docref(NULL, E_WARNING, "Invalid SolrParams Index %ld. HashTable index does not exist.", params_index); php_error_docref(NULL, E_WARNING, SOLR_ERROR_1008_MSG, SOLR_FILE_LINE_FUNC); return FAILURE; } return SUCCESS; } /* }}} */ PHP_SOLR_API int solr_fetch_function_entry(zval *objptr, solr_function_t **solr_function) { zval rv; zval *id = zend_read_property(Z_OBJCE_P(objptr), OBJ_FOR_PROP(objptr), SOLR_INDEX_PROPERTY_NAME, sizeof(SOLR_INDEX_PROPERTY_NAME) - 1, 1, &rv); long int params_index = Z_LVAL_P(id); *solr_function = NULL; if ((*solr_function = zend_hash_index_find_ptr(SOLR_GLOBAL(functions), params_index)) == NULL) { php_error_docref(NULL, E_WARNING, "Invalid solr_function Index %ld. HashTable index does not exist.", params_index); php_error_docref(NULL, E_WARNING, SOLR_ERROR_1008_MSG, SOLR_FILE_LINE_FUNC); return FAILURE; } return SUCCESS; } /* {{{ PHP_SOLR_API void solr_destroy_function(zval *solr_function) */ PHP_SOLR_API void solr_destroy_function(zval *solr_function) { solr_function_t *function = (solr_function_t *) Z_PTR_P(solr_function); zend_hash_destroy(function->params); pefree(function->params, SOLR_FUNCTIONS_PERSISTENT); #ifdef PHP_7 pefree(function, SOLR_FUNCTIONS_PERSISTENT); #endif } /* }}} */ /* {{{ PHP_SOLR_API xmlDocPtr solr_xml_create_xml_doc(const xmlChar *root_node_name, xmlNode **root_node_ptr) */ PHP_SOLR_API xmlDocPtr solr_xml_create_xml_doc(const xmlChar *root_node_name, xmlNode **root_node_ptr) { xmlNs *ns = NULL; xmlDoc *doc_ptr = xmlNewDoc((xmlChar *) "1.0"); xmlNode *root_node = xmlNewNode(ns, root_node_name); xmlDocSetRootElement(doc_ptr, root_node); if (root_node_ptr) { *root_node_ptr = root_node; } return doc_ptr; } /* }}} */ /** * escapes strings with characters that are part of the Lucene query syntax * * @sbuilder is a solr_string_t pointer used to store the escape char sequence * @unescaped is the unescaped string. It must be null terminated * @unescaped_length is the original length of the unescaped_string */ /* {{{ PHP_SOLR_API void solr_escape_query_chars(solr_string_t *sbuilder, solr_char_t *unescaped, long int unescaped_length) */ PHP_SOLR_API void solr_escape_query_chars(solr_string_t *sbuilder, solr_char_t *unescaped, long int unescaped_length) { register int i = 0; /** * Lucene supports escaping special characters that are part of the query syntax. * * The current list special characters are * + - && || ! ( ) { } [ ] ^ " ~ * ? : \ / * * These characters are part of the query syntax and must be escaped */ for (i = 0; i < unescaped_length; i++) { enter_switchboard : switch(unescaped[i]) { case '\\' : case '+' : case '-' : case '!' : case '(' : case ')' : case ':' : case '/' : case '^' : case '[' : case ']' : case '"' : case '{' : case '}' : case '~' : case '*' : case '?' : case ';' : { solr_string_appendc(sbuilder, '\\'); } break; case '|' : /* || */ { if ('|' == unescaped[i+1]) { solr_string_appendc(sbuilder, '\\'); solr_string_append_const(sbuilder, "||"); i += 2; goto enter_switchboard; } } break; case '&' : /* && */ { if ('&' == unescaped[i+1]) { solr_string_appendc(sbuilder, '\\'); solr_string_append_const(sbuilder, "&&"); i += 2; goto enter_switchboard; } } break; default : /* The current character is not a special character */ { /* Do nothing. Just append the character as is */ } } /* END switch(unescaped[i]) */ solr_string_appendc(sbuilder, unescaped[i]); } /* END for (i = 0; i < unescaped_length; i++) { */ } /* }}} */ /******************************************************************************/ /* SOLR XML RESPONSE DIGEST DATA TYPES AND FUNCTIONS */ /******************************************************************************/ /* {{{ solr_doc_encode_t, solr_php_encode_t, solr_encoding_type_t, solr_php_encode_func_t, solr_document_field_encode_func_t */ typedef enum { SOLR_DOC_ENCODE_START = 0, SOLR_DOC_ENCODE_FIELDS = 1, SOLR_DOC_ENCODE_FIELD = 2, SOLR_DOC_ENCODE_END } solr_doc_encode_t; typedef enum { SOLR_ENCODE_START = 0, SOLR_ENCODE_NULL = 1, SOLR_ENCODE_BOOL = 2, SOLR_ENCODE_INT = 3, SOLR_ENCODE_FLOAT = 4, SOLR_ENCODE_STRING = 5, SOLR_ENCODE_ARRAY = 6, SOLR_ENCODE_OBJECT = 7, SOLR_ENCODE_DOC = 8, SOLR_ENCODE_RESULT = 9, SOLR_ENCODE_END } solr_php_encode_t; typedef enum { SOLR_ENCODE_STANDALONE = 0, SOLR_ENCODE_OBJECT_PROPERTY = 1, SOLR_ENCODE_ARRAY_KEY = 2, SOLR_ENCODE_ARRAY_INDEX = 3 } solr_encoding_type_t; typedef void (*solr_php_encode_func_t)(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode); typedef void (*solr_document_field_encode_func_t)(const xmlNode *node, xmlNode *field); /* }}} */ /* {{{ Macros for XML transcoding */ /* Serializes the current XML node */ #define solr_encode_xml_node(__node, __buf, __enc_type, __arr_idx, __mode) solr_encoder_functions[solr_get_xml_type((__node))]((__node),(__buf), (__enc_type), (__arr_idx), (__mode)) #define solr_write_object_closer(__buf) solr_string_append_const((__buf), "}") #define solr_write_array_closer(__buf) solr_string_append_const((__buf), "}") #define solr_write_root_object_closer(__buf) solr_string_append_const((__buf), "}") /* }}} */ /* {{{ static void solr_encode_* prototypes */ static void solr_encode_null(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode); static void solr_encode_bool(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode); static void solr_encode_int(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode); static void solr_encode_float(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode); static void solr_encode_string(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode); static void solr_encode_array(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode); static void solr_encode_object(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode); static void solr_encode_document(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode); static void solr_encode_result(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode); static void solr_encode_document_field_simple(const xmlNode *fieldNode, xmlNode *field); static void solr_encode_document_field_complex(const xmlNode *fieldNode, xmlNode *field); /* }}} */ /* {{{ global variables solr_encoder_functions[], solr_document_field_encoders[] */ static solr_php_encode_func_t solr_encoder_functions[] = { solr_encode_string, solr_encode_null, solr_encode_bool, solr_encode_int, solr_encode_float, solr_encode_string, solr_encode_array, solr_encode_object, solr_encode_document, solr_encode_result, NULL }; static solr_document_field_encode_func_t solr_document_field_encoders[] = { solr_encode_document_field_simple, /* maps to SOLR_SIMPLE_FIELD */ solr_encode_document_field_complex, /* maps to SOLR_COMPLEX_FIELD */ NULL }; /* }}} */ /* {{{ Constants and Macros for handling node types */ #define SOLR_SIMPLE_FIELD 0 #define SOLR_COMPLEX_FIELD 1 #define solr_xml_field_node_type(node) (xmlStrEqual((node)->name, (xmlChar *)"arr")? SOLR_COMPLEX_FIELD : SOLR_SIMPLE_FIELD) #define solr_encode_document_field(field_in, field_out) solr_document_field_encoders[solr_xml_field_node_type((field_in))]((field_in), (field_out)) /* }}} */ /* Used to figure out now many properties or elements there are in an object or an array */ /* {{{ static inline int solr_get_node_size(const xmlNode *data_node) */ static inline int solr_get_node_size(const xmlNode *data_node) { register int size = 0; xmlNode *curr_node = data_node->children; while(curr_node != NULL) { if (XML_ELEMENT_NODE == curr_node->type) { size++; } curr_node = curr_node->next; } return size; } /* }}} */ /* {{{ static inline int solr_get_xml_type(xmlNode *node) */ static inline int solr_get_xml_type(xmlNode *node) { solr_char_t *node_name = (solr_char_t *) node->name; if (!node_name) { return SOLR_ENCODE_STRING; } if (!strcmp(node_name, "str")) { return SOLR_ENCODE_STRING; } else if (!strcmp(node_name, "int") || !strcmp(node_name, "long") || !strcmp(node_name, "short") || !strcmp(node_name, "byte")) { return SOLR_ENCODE_INT; } else if (!strcmp(node_name, "double") || !strcmp(node_name, "float")) { return SOLR_ENCODE_FLOAT; } else if (!strcmp(node_name, "lst")) { return SOLR_ENCODE_OBJECT; } else if (!strcmp(node_name, "arr")) { return SOLR_ENCODE_ARRAY; } else if (!strcmp(node_name, "bool")) { return SOLR_ENCODE_BOOL; } else if (!strcmp(node_name, "null")) { return SOLR_ENCODE_NULL; } else if (!strcmp(node_name, "result")) { return SOLR_ENCODE_RESULT; }else if (!strcmp(node_name, "doc")) { return SOLR_ENCODE_OBJECT; } else { return SOLR_ENCODE_STRING; } } /* }}} */ /* {{{ static inline void solr_write_variable_opener(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index) */ static inline void solr_write_variable_opener(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index) { switch(enc_type) { case SOLR_ENCODE_OBJECT_PROPERTY : /* fall through */ case SOLR_ENCODE_ARRAY_KEY : { solr_char_t *object_name = "_undefined_property_name"; xmlAttr *name_attr = node->properties; /* get the contents of the name attribute */ if (name_attr) { object_name = (solr_char_t *) solr_xml_get_node_contents(name_attr); } solr_string_append_const(buffer, "s:"); solr_string_append_long(buffer, strlen(object_name)); solr_string_append_const(buffer, ":\""); solr_string_appends(buffer, object_name, strlen(object_name)); solr_string_append_const(buffer, "\";"); } break; case SOLR_ENCODE_ARRAY_INDEX : { solr_string_append_const(buffer, "i:"); solr_string_append_long(buffer, array_index); solr_string_appendc(buffer, ';'); } break; default : { /* do nothing */ } break; } } /* }}} */ /* {{{ static void solr_write_object_opener(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index) */ static void solr_write_object_opener(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index) { int size = solr_get_node_size(node); solr_write_variable_opener(node, buffer, enc_type, array_index); solr_string_append_const(buffer, "O:10:\"SolrObject\":"); solr_string_append_long(buffer, size); solr_string_append_const(buffer, ":{"); } /* }}} */ /* {{{ static void solr_write_solr_document_opener(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, int size) */ static void solr_write_solr_document_opener(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, int size) { solr_write_variable_opener(node, buffer, enc_type, array_index); solr_string_append_const(buffer, "C:12:\"SolrDocument\":"); solr_string_append_long(buffer, size); solr_string_append_const(buffer, ":{"); } /* }}} */ /* {{{ static void solr_write_array_opener(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index) */ static void solr_write_array_opener(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index) { int size = solr_get_node_size(node); solr_write_variable_opener(node, buffer, enc_type, array_index); solr_string_append_const(buffer, "a:"); solr_string_append_long(buffer, size); solr_string_append_const(buffer, ":{"); } /* }}} */ static void solr_serialize_solr_document(const xmlNode *node, solr_string_t *dest); static void solr_encode_solr_document_children(const xmlNode *node, xmlNode* builder_node, int child_docs_found); static void solr_encode_solr_document(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode); static void solr_serialize_solr_document(const xmlNode *node, solr_string_t *dest) { xmlChar *doc_txt_buffer = NULL; int doc_txt_len = 0; xmlNode *solr_document_node = NULL; xmlDoc *doc_ptr = solr_xml_create_xml_doc((xmlChar *) "solr_document", &solr_document_node); xmlNode *fields_node = xmlNewChild(solr_document_node, NULL, (xmlChar *) "fields", NULL); xmlNode *curr_node = node->children; int format = 1; int child_docs_found = 0; while(curr_node != NULL) { if (XML_ELEMENT_NODE == curr_node->type) { if (strcmp((const char *)curr_node->name, "doc") == 0) { child_docs_found++; } else { xmlNode *field = xmlNewChild(fields_node, NULL, (xmlChar *)"field", NULL); solr_encode_document_field(curr_node, field); } } curr_node = curr_node->next; } if (child_docs_found > 0) { solr_encode_solr_document_children(node, solr_document_node, child_docs_found); } /* We have written all the fields to the document */ /* Dumping the document from memory to the buffer */ xmlDocDumpFormatMemoryEnc(doc_ptr, &doc_txt_buffer, &doc_txt_len, "UTF-8", format); solr_string_appends_ex(dest, (solr_char_t *)doc_txt_buffer, doc_txt_len); xmlFreeDoc(doc_ptr); xmlFree(doc_txt_buffer); } /* {{{ static void solr_encode_document_children(const xmlNode *node, solr_string_t* buffer, int child_docs_found, long int parse_mode) encodes the doc/doc child/nested documents */ static void solr_encode_solr_document_children(const xmlNode *node, xmlNode* builder_node, int child_docs_found) { int current_index = 0; xmlXPathContext *xpathctxt = NULL; const xmlChar *xpath_expression = (xmlChar *) "child::doc"; xmlXPathObject *xpathObj = NULL; xmlNodeSet *result = NULL; xmlNode *child_docs_node = NULL; xpathctxt = xmlXPathNewContext(node->doc); xpathctxt->node = (xmlNodePtr) node; xpathObj = xmlXPathEval(xpath_expression, xpathctxt); result = xpathObj->nodesetval; child_docs_found = result->nodeNr; child_docs_node = xmlNewChild(builder_node, NULL, (xmlChar *)"child_docs", NULL); for (current_index=0; current_index < child_docs_found; current_index++) { zend_string *encoded_str = NULL; solr_string_t tmp_buffer; solr_string_t tmp_s_buffer; memset(&tmp_buffer, 0, sizeof(solr_string_t)); memset(&tmp_s_buffer, 0, sizeof(solr_string_t)); solr_serialize_solr_document(result->nodeTab[current_index], &tmp_buffer); solr_string_append_const(&tmp_s_buffer, "C:12:\"SolrDocument\":"); solr_string_append_long(&tmp_s_buffer, tmp_buffer.len); solr_string_append_const(&tmp_s_buffer, ":{"); solr_string_appends_ex(&tmp_s_buffer, tmp_buffer.str, tmp_buffer.len); solr_write_object_closer(&tmp_s_buffer); encoded_str = php_base64_encode((const unsigned char*)tmp_s_buffer.str, tmp_s_buffer.len); xmlNewChild(child_docs_node, NULL, (const xmlChar *) "dochash", (xmlChar *)encoded_str->val); solr_string_free_ex(&tmp_buffer); solr_string_free_ex(&tmp_s_buffer); zend_string_free(encoded_str); } } /* }}} */ /** * * The @enc_type parameter must be SOLR_ENCODE_ARRAY_INDEX */ /* {{{ static void solr_encode_solr_document(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode) */ static void solr_encode_solr_document(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode) { solr_string_t doc_serialized_buffer; memset(&doc_serialized_buffer, 0, sizeof(solr_string_t)); solr_serialize_solr_document(node, &doc_serialized_buffer); solr_write_solr_document_opener(NULL, buffer, enc_type, array_index, doc_serialized_buffer.len); solr_string_appends(buffer, (char *) doc_serialized_buffer.str, doc_serialized_buffer.len); solr_write_object_closer(buffer); solr_string_free(&doc_serialized_buffer); } /* }}} */ /* {{{ static void solr_write_object_opener(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index) */ static void solr_write_object_opener_child_doc(const xmlNode *node, int num_child_docs ,solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index) { int size = solr_get_node_size(node) - num_child_docs + 1; solr_write_variable_opener(node, buffer, enc_type, array_index); solr_string_append_const(buffer, "O:10:\"SolrObject\":"); solr_string_append_long(buffer, size); solr_string_append_const(buffer, ":{"); } /* }}} */ /* {{{ static void solr_encode_document_children(const xmlNode *node, solr_string_t* buffer, int child_docs_found, long int parse_mode) encodes the doc/doc child/nested documents ONLY FOR SolrObject */ static void solr_encode_document_children(const xmlNode *node, solr_string_t* buffer, int child_docs_found, long int parse_mode) { int current_index = 0; xmlXPathContext *xpathctxt = NULL; const xmlChar *xpath_expression = (xmlChar *) "child::doc"; xmlXPathObject *xpathObj = NULL; xmlNodeSet *result = NULL; solr_php_encode_func_t document_encoder_functions[] = { solr_encode_document, solr_encode_solr_document, NULL }; solr_string_append_const(buffer, "s:"); solr_string_append_long(buffer, sizeof("_childDocuments_")-1); solr_string_append_const(buffer, ":\""); solr_string_appends(buffer, "_childDocuments_", sizeof("_childDocuments_")-1); solr_string_append_const(buffer, "\";"); solr_string_append_const(buffer, "a:"); solr_string_append_long(buffer, child_docs_found); solr_string_append_const(buffer, ":{"); xpathctxt = xmlXPathNewContext(node->doc); xpathctxt->node = (xmlNodePtr) node; xpathObj = xmlXPathEval(xpath_expression, xpathctxt); result = xpathObj->nodesetval; child_docs_found = result->nodeNr; for (current_index=0; current_index < child_docs_found; current_index++) { document_encoder_functions[parse_mode](result->nodeTab[current_index], buffer, SOLR_ENCODE_ARRAY_INDEX, current_index, parse_mode); } solr_write_array_closer(buffer); } /* }}} */ /* {{{ static void solr_encode_document(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode) encodes/serializes the element result/doc */ static void solr_encode_document(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode) { xmlNode *curr_node = NULL; int child_docs_found = 0; solr_string_t inner_buffer; memset(&inner_buffer, 0, sizeof(solr_string_t)); curr_node = node->children; while(curr_node != NULL) { if (XML_ELEMENT_NODE == curr_node->type) { if (strcmp((const char*) curr_node->name, "doc") == 0) { /* skip doc/doc elements to be processed later */ child_docs_found++; } else { solr_encode_xml_node(curr_node, &inner_buffer, SOLR_ENCODE_OBJECT_PROPERTY, 0L, parse_mode); } } curr_node = curr_node->next; } if (child_docs_found > 0){ solr_encode_document_children(node, &inner_buffer, child_docs_found, parse_mode); /** * write and calculate proper object opener * because the object number of properties depends on whether there are child documents involved */ solr_write_object_opener_child_doc(node, child_docs_found, buffer, enc_type, array_index); } else { solr_write_object_opener(node, buffer, enc_type, array_index); } solr_string_appends_ex(buffer, inner_buffer.str, inner_buffer.len); solr_write_object_closer(buffer); solr_string_free_ex(&inner_buffer); } /* }}} */ /** * Handles simple data types like strings, integers, booleans etc. */ /* {{{ static void solr_encode_document_field_simple(const xmlNode *fieldNode, xmlNode *field) */ static void solr_encode_document_field_simple(const xmlNode *fieldNode, xmlNode *field) { xmlChar *fieldname = solr_xml_get_node_contents(fieldNode->properties); xmlChar *field_value = xmlEncodeEntitiesReentrant(fieldNode->doc, solr_xml_get_node_contents(fieldNode)); xmlNewChild(field, NULL, (xmlChar *) "field_value", field_value); xmlNewProp(field, (xmlChar *) "name", fieldname); xmlFree(field_value); } /* }}} */ /* Handles complex data types like arrays */ /* {{{ static void solr_encode_document_field_complex(const xmlNode *fieldNode, xmlNode *field) */ static void solr_encode_document_field_complex(const xmlNode *fieldNode, xmlNode *field) { xmlChar *fieldname = solr_xml_get_node_contents(fieldNode->properties); xmlNode *current_value = fieldNode->children; while(current_value != NULL) { if (current_value->type == XML_ELEMENT_NODE) { xmlChar *field_value = xmlEncodeEntitiesReentrant(fieldNode->doc, solr_xml_get_node_contents(current_value)); xmlNewChild(field, NULL, (xmlChar *) "field_value", field_value); xmlFree(field_value); } current_value = current_value->next; } xmlNewProp(field, (xmlChar *) "name", fieldname); } /* }}} */ /* {{{ static void solr_encode_result(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode) */ static void solr_encode_result(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode) { xmlAttr *properties = node->properties; solr_char_t *object_name = (solr_char_t *) node->name; solr_char_t *num_found = NULL; solr_char_t *start = NULL; solr_char_t *max_score = NULL; solr_php_encode_func_t document_encoder_functions[] = { solr_encode_document, solr_encode_solr_document, NULL }; xmlAttr *curr_prop = properties; xmlXPathContext *xpathctxt = NULL; const xmlChar *xpath_expression = (xmlChar *) "child::doc"; xmlXPathObject *xpathObj = NULL; xmlNodeSet *result = NULL; long int document_count = 0; while(curr_prop != NULL) { if (solr_xml_match_node(curr_prop, "numFound")) { num_found = (solr_char_t *) solr_xml_get_node_contents(curr_prop); } if (solr_xml_match_node(curr_prop, "start")) { start = (solr_char_t *) solr_xml_get_node_contents(curr_prop); } if (solr_xml_match_node(curr_prop, "name")) { object_name = (solr_char_t *) solr_xml_get_node_contents(curr_prop); } if (solr_xml_match_node(curr_prop, "maxScore")) { max_score = (solr_char_t *) solr_xml_get_node_contents(curr_prop); } curr_prop = curr_prop->next; } xpathctxt = xmlXPathNewContext(node->doc); xpathctxt->node = (xmlNodePtr) node; xpathObj = xmlXPathEval(xpath_expression, xpathctxt); result = xpathObj->nodesetval; document_count = result->nodeNr; solr_string_append_const(buffer, "s:"); solr_string_append_long(buffer, strlen(object_name)); solr_string_append_const(buffer, ":\""); solr_string_appends(buffer, object_name, strlen(object_name)); solr_string_append_const(buffer, "\";"); solr_string_append_const(buffer, "O:10:\"SolrObject\":"); if (max_score) { solr_string_append_long(buffer, 4); /* numFound, start, docs, maxScore properties */ } else { solr_string_append_long(buffer, 3); /* numFound, start, docs properties */ } solr_string_append_const(buffer, ":{"); /* Object Opener for response */ /* Writing the numFound property */ solr_string_append_const(buffer, "s:"); solr_string_append_long(buffer, sizeof("numFound")-1); solr_string_append_const(buffer, ":\""); solr_string_appends(buffer, "numFound", sizeof("numFound")-1); solr_string_append_const(buffer, "\";"); solr_string_append_const(buffer, "i:"); solr_string_appends(buffer, num_found, solr_strlen(num_found)); solr_string_appendc(buffer, ';'); /* Writing the start property */ solr_string_append_const(buffer, "s:"); solr_string_append_long(buffer, sizeof("start")-1); solr_string_append_const(buffer, ":\""); solr_string_appends(buffer, "start", sizeof("start")-1); solr_string_append_const(buffer, "\";"); solr_string_append_const(buffer, "i:"); solr_string_appends(buffer, start, solr_strlen(start)); solr_string_appendc(buffer, ';'); /* writing max score property */ if (max_score) { solr_string_append_const(buffer, "s:"); solr_string_append_long(buffer, sizeof("maxScore")-1); solr_string_append_const(buffer, ":\""); solr_string_appends(buffer, "maxScore", sizeof("maxScore")-1); solr_string_append_const(buffer, "\";"); solr_string_append_const(buffer, "d:"); solr_string_appends(buffer, max_score, solr_strlen(max_score)); solr_string_appendc(buffer, ';'); } /* Writing the docs property */ solr_string_append_const(buffer, "s:"); solr_string_append_long(buffer, sizeof("docs")-1); solr_string_append_const(buffer, ":\""); solr_string_appends(buffer, "docs", sizeof("docs")-1); solr_string_append_const(buffer, "\";"); if (document_count) { /* Grab all the first /response/result/doc node */ xmlNode *curr_doc = node->children; long int curr_doc_index = 0L; /* Array opener */ solr_string_append_const(buffer, "a:"); solr_string_append_long(buffer, document_count); solr_string_append_const(buffer, ":{"); while(curr_doc != NULL) { /* Absolutely no assumptions. At least for now. */ if (XML_ELEMENT_NODE == curr_doc->type && solr_xml_match_node(curr_doc, "doc")) { /* This is where you decided whether to use SolrDocument or StdClass */ /* parse_mode value of 0 creates SolrObject; 1 creates SolrDocument */ document_encoder_functions[parse_mode](curr_doc, buffer, SOLR_ENCODE_ARRAY_INDEX, curr_doc_index, parse_mode); curr_doc_index++; } curr_doc = curr_doc->next; } solr_write_array_closer(buffer); /* Array closer */ } else { solr_string_append_const(buffer, "b:0;"); /* This means there are no docs */ } solr_write_object_closer(buffer); /* Object closer */ xmlXPathFreeContext(xpathctxt); xmlXPathFreeObject(xpathObj); } /* }}} */ /* {{{ static void solr_encode_null(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode) */ static void solr_encode_null(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode) { /* SolrObject should not contain nulls because of how magic functionality is implemented */ solr_write_variable_opener(node, buffer, enc_type, array_index); /* Setting nulls to boolean false */ solr_string_append_const(buffer, "b:0;"); } /* }}} */ /* {{{ static void solr_encode_bool(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode) */ static void solr_encode_bool(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode) { solr_char_t *data_value = (solr_char_t *) solr_xml_get_node_contents(node); long int boolean_value = (!strcmp("true", data_value))? 1 : 0; solr_write_variable_opener(node, buffer, enc_type, array_index); solr_string_append_const(buffer, "b:"); solr_string_append_long(buffer, boolean_value); solr_string_appendc(buffer, ';'); } /* }}} */ /* {{{ static void solr_encode_int(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode) */ static void solr_encode_int(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode) { solr_char_t *data_value = (solr_char_t *) solr_xml_get_node_contents(node); size_t data_value_len = solr_strlen(data_value); solr_write_variable_opener(node, buffer, enc_type, array_index); solr_string_append_const(buffer, "i:"); solr_string_appends(buffer, data_value, data_value_len); solr_string_appendc(buffer, ';'); } /* }}} */ /* {{{ static void solr_encode_float(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode) */ static void solr_encode_float(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode) { solr_char_t *data_value = (solr_char_t *) solr_xml_get_node_contents(node); size_t data_value_len = solr_strlen(data_value); solr_write_variable_opener(node, buffer, enc_type, array_index); solr_string_append_const(buffer, "d:"); if (strcmp(data_value, "NaN" ) == 0) { data_value = (solr_char_t *)"NAN"; } solr_string_appends(buffer, data_value, data_value_len); solr_string_appendc(buffer, ';'); } /* }}} */ /* {{{ static void solr_encode_string(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode) */ static void solr_encode_string(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode) { solr_char_t *data_value = (solr_char_t *) solr_xml_get_node_contents(node); size_t data_value_len = solr_strlen(data_value); solr_write_variable_opener(node, buffer, enc_type, array_index); solr_string_append_const(buffer, "s:"); solr_string_append_long(buffer, data_value_len); solr_string_append_const(buffer, ":\""); solr_string_appends(buffer, data_value, data_value_len); solr_string_append_const(buffer, "\";"); } /* }}} */ /* {{{ static void solr_encode_array(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode) */ static void solr_encode_array(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode) { xmlNode *curr_node = NULL; long int current_index = 0L; solr_write_array_opener(node, buffer, enc_type, array_index); curr_node = node->children; while(curr_node != NULL) { if (XML_ELEMENT_NODE == curr_node->type) { solr_encode_xml_node(curr_node, buffer, SOLR_ENCODE_ARRAY_INDEX, current_index, parse_mode); current_index++; } curr_node = curr_node->next; } solr_write_array_closer(buffer); } /* }}} */ /* {{{ static void solr_encode_object(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode) */ static void solr_encode_object(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index, long int parse_mode) { xmlNode *curr_node = NULL; solr_write_object_opener(node, buffer, enc_type, array_index); curr_node = node->children; while(curr_node != NULL) { if (XML_ELEMENT_NODE == curr_node->type) { solr_encode_xml_node(curr_node, buffer, SOLR_ENCODE_OBJECT_PROPERTY, 0L, parse_mode); } curr_node = curr_node->next; } solr_write_object_closer(buffer); } /* }}} */ /** * Used to digest Xml response messages from Solr * */ /* {{{ PHP_SOLR_API void solr_encode_generic_xml_response(solr_string_t *buffer, const solr_char_t *serialized, int size, long int parse_mode) */ PHP_SOLR_API void solr_encode_generic_xml_response(solr_string_t *buffer, const solr_char_t *serialized, int size, long int parse_mode) { xmlDoc *doc = xmlReadMemory(serialized, size, NULL, "UTF-8", XML_PARSE_RECOVER); xmlNode *root = NULL; if (!doc) { php_error_docref(NULL, E_WARNING, "Error loading XML document"); return; } root = xmlDocGetRootElement(doc); if (!root) { xmlFreeDoc(doc); php_error_docref(NULL, E_WARNING, "Error loading root of XML document"); return; } parse_mode = ((parse_mode < 0L) ? 0L : ((parse_mode > 1L) ? 1L : parse_mode)); solr_encode_object(root, buffer, SOLR_ENCODE_STANDALONE, 0L, parse_mode); if (buffer->len == 0) { php_error_docref(NULL, E_WARNING, "Error parsing XML document"); } xmlFreeDoc(doc); } /* }}} */ /* {{{ PHP_SOLR_API int solr_is_supported_response_writer(const solr_char_t * response_writer, int length) */ PHP_SOLR_API int solr_is_supported_response_writer(const solr_char_t * response_writer, int length) { if (length < 1) { return 0; } if (0 == strcmp(response_writer, SOLR_PHP_SERIALIZED_RESPONSE_WRITER)) { return 1; } if (0 == strcmp(response_writer, SOLR_XML_RESPONSE_WRITER)) { return 1; } if (0 == strcmp(response_writer, SOLR_JSON_RESPONSE_WRITER)) { return 1; } return 0; } /* }}} */ /* {{{ PHP_SOLR_API solr_char_t *solr_get_json_error_msg(solr_json_error_codes_t error_code) */ PHP_SOLR_API solr_char_t *solr_get_json_error_msg(solr_json_error_codes_t error_code) { switch(error_code) { case SOLR_JSON_ERROR_DEPTH: return "JSON maximum recursion depth was exceeded"; break; case SOLR_JSON_ERROR_STATE_MISMATCH: return "JSON error state mismatch"; break; case SOLR_JSON_ERROR_CTRL_CHAR: return "JSON control character was encountered"; break; case SOLR_JSON_ERROR_SYNTAX: return "JSON syntax error"; break; case SOLR_JSON_ERROR_UTF8: return "JSON UTF8 error"; break; default : return "JSON unknown error"; break; } } /* }}} */ /* {{{ PHP_SOLR_API int solr_json_to_php_native(solr_string_t *buffer, const solr_char_t *json_string, int json_string_length) */ PHP_SOLR_API int solr_json_to_php_native(solr_string_t *buffer, const solr_char_t *json_string, int json_string_length) { /* todo php7 review if we ever need that indirection with ret_val */ /* JSON recursion depth. default is 512 */ long recursion_depth = 1024L; long json_error = 0L; php_serialize_data_t var_hash; smart_str serialize_buffer = {0}; /* return value for the function */ zval json_decode_ret_val, *json_decode_ret_val_ptr; zend_uchar json_decode_ret_val_type = IS_NULL; json_decode_ret_val_ptr = &json_decode_ret_val; php_json_decode(&json_decode_ret_val, (char *) json_string, json_string_length, 1, recursion_depth); json_error = solr_get_json_last_error(); /* Why ? todo investigate */ /* solr_string_set(buffer, "i:99;", sizeof("i:99;")); */ if (json_error > 0) { zval_dtor(&json_decode_ret_val); php_error_docref(NULL, E_WARNING, "JSON error. JSON->PHP serialization error"); return (int) json_error; } memset(&var_hash, 0, sizeof(php_serialize_data_t)); PHP_VAR_SERIALIZE_INIT(var_hash); php_var_serialize(&serialize_buffer, &json_decode_ret_val, &var_hash); json_decode_ret_val_type = Z_TYPE_P(json_decode_ret_val_ptr); zval_dtor(&json_decode_ret_val); solr_string_set(buffer, serialize_buffer.s->val, serialize_buffer.s->len); PHP_VAR_SERIALIZE_DESTROY(var_hash); smart_str_free(&serialize_buffer); /* return value should not be of NULL type. NULL means an error has occurred */ if (json_decode_ret_val_type == IS_NULL) { php_error_docref(NULL, E_WARNING, "JSON error. Error occurred in php_json_decode(). Raw JSON string is \n %s \n", (char *) json_string); /* json_error always fails to detect an error. * todo investigate */ return (int) SOLR_JSON_ERROR_SERIALIZATION; } return (int) json_error; } /* }}} */ PHP_SOLR_API long solr_get_json_last_error(void) { long json_error; zval json_last_error_ret_val, *object_p; zval *json_last_error_params = NULL; zval json_last_error_function_name; ZVAL_STRING(&json_last_error_function_name, "json_last_error"); /* object instance to perform the method call */ object_p = (zval *) NULL; call_user_function(EG(function_table), object_p, &json_last_error_function_name, &json_last_error_ret_val, 0, json_last_error_params); json_error = Z_LVAL(json_last_error_ret_val); zval_dtor(&json_last_error_ret_val); #ifdef PHP_7 zval_dtor(&json_last_error_function_name); #endif return json_error; } static inline int solr_pcre_replace_into_buffer(solr_string_t *buffer, char * search, char *replace) { zend_string *result; int limit = -1; #if PHP_VERSION_ID >= 70300 size_t replace_count = -1; #else int replace_count = -1; #endif zend_string *regex_str = zend_string_init(search, strlen(search), 0); zend_string *subject_str = zend_string_init(buffer->str, buffer->len, 0); #if PHP_VERSION_ID >= 70200 zend_string *replace_str = zend_string_init(replace, strlen(replace), 0); #else zval replace_val; ZVAL_STRING(&replace_val, replace); #endif result = php_pcre_replace( regex_str, subject_str, buffer->str, buffer->len, #if PHP_VERSION_ID >= 70200 replace_str, #else &replace_val, 0, #endif limit, &replace_count ); solr_string_set_ex(buffer, (solr_char_t *)result->val, (size_t)result->len); /* fprintf(stdout, "%s", buffer->str); */ efree(result); #if PHP_VERSION_ID >= 70200 zend_string_release(replace_str); #else zval_ptr_dtor(&replace_val); #endif zend_string_release(regex_str); zend_string_release(subject_str); return SUCCESS; } /* serialized array to serialized object */ PHP_SOLR_API int solr_sarray_to_sobject(solr_string_t *buffer) { return solr_pcre_replace_into_buffer(buffer, "/a\\:([0-9]+):{s/i", "O:10:\"SolrObject\":\\1:{s"); } /* serialized object to serialized array */ PHP_SOLR_API int solr_sobject_to_sarray(solr_string_t *buffer) { return solr_pcre_replace_into_buffer(buffer, "/O:10:\"SolrObject\":([0-9]+):{s/i", "a:\\1:{s"); } /* }}} */ /* todo document and block this */ PHP_SOLR_API int solr_solrfunc_update_string(zval *obj, solr_char_t *key, int key_len, solr_char_t *value, int value_len) { solr_function_t *function; solr_string_t *string; #ifdef PHP_7 string = pemalloc(sizeof(solr_string_t), SOLR_FUNCTIONS_PERSISTENT); #endif memset(string, 0, sizeof(solr_string_t)); if (solr_fetch_function_entry(obj, &function) == FAILURE) { return FAILURE; } solr_string_set(string, (solr_char_t *)value, value_len); if (zend_hash_str_update_ptr(function->params, key, key_len, (void *)string) == NULL ) { solr_string_free(string); return FAILURE; } return SUCCESS; } PHP_SOLR_API int solr_solrfunc_fetch_string(zval *obj, solr_char_t *key, int key_len, solr_string_t **string) { solr_function_t *function; if (solr_fetch_function_entry(obj, &function) == FAILURE) { return FAILURE; } if ((*string = zend_hash_str_find_ptr(function->params, key, key_len)) == NULL) { return FAILURE; } return SUCCESS; } PHP_SOLR_API int solr_solrfunc_display_string(zval *obj, solr_char_t *key, int key_len, zval **return_value) { solr_string_t *field_string_ptr = NULL; memset(&field_string_ptr, 0, sizeof(solr_string_t *)); if (solr_solrfunc_fetch_string(obj, key, key_len, &field_string_ptr) == SUCCESS) { ZVAL_STRINGL(*return_value, field_string_ptr->str, field_string_ptr->len); return SUCCESS; } else { php_error_docref(NULL, E_ERROR, "Unable to fetch string"); return FAILURE; } } PHP_SOLR_API void solr_solrfunc_to_string(solr_function_t *function, solr_string_t **dest) { solr_string_t *buffer = *dest; solr_string_appends(buffer, (solr_char_t *)"{!", sizeof("{!")-1); solr_string_appends(buffer, function->name, function->name_length); solr_string_appendc(buffer, ' '); solr_string_t *value; zend_string *key; zend_ulong num_idx; ZEND_HASH_FOREACH_KEY_PTR(function->params, num_idx, key, value) { (void)num_idx; /* silent -Wunused-but-set-variable */ /* key is only maintained internally */ if (key) { solr_string_appends(buffer, key->val, key->len-1); } solr_string_appendc(buffer, '='); if (strpbrk(value->str, " ") != NULL && strpbrk(value->str,"'") == NULL) { solr_string_appendc(buffer, '\''); solr_string_append_solr_string (buffer, value); solr_string_appendc(buffer, '\''); } else { solr_string_append_solr_string (buffer, value); } solr_string_appendc(buffer, ' '); } ZEND_HASH_FOREACH_END(); solr_string_remove_last_char(buffer); solr_string_appendc(buffer, '}'); /* todo handle localParams argument */ } PHP_SOLR_API void solr_destroy_ustream_ex(solr_ustream_t *stream) { if (stream->content_info->filename.len > 0) { solr_string_free(&stream->content_info->filename); } pefree(stream->content_info, 0); pefree(stream, 0); } PHP_SOLR_API void solr_destroy_ustream_zv(zval *obj) { solr_ustream_t *entry = Z_PTR_P(obj); solr_destroy_ustream_ex(entry); } PHP_SOLR_API int solr_fetch_ustream_entry(zval *objptr, solr_ustream_t **stream_entry) { zval rv, *index_zv; zend_ulong index = 0; index_zv = zend_read_property(Z_OBJCE_P(objptr), OBJ_FOR_PROP(objptr), SOLR_INDEX_PROPERTY_NAME, sizeof(SOLR_INDEX_PROPERTY_NAME)-1, 1, &rv); index = Z_LVAL_P(index_zv); if ((*stream_entry = zend_hash_index_find_ptr(SOLR_GLOBAL(ustreams), index)) == NULL) { php_error_docref(NULL, E_WARNING, "Invalid Update Stream Index %ld. HashTable index does not exist.", index); php_error_docref(NULL, E_WARNING, SOLR_ERROR_1008_MSG, SOLR_FILE_LINE_FUNC); return FAILURE; } return SUCCESS; } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: fdm=marker * vim: noet sw=4 ts=4 */