1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) The PHP Group                                          |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | http://www.php.net/license/3_01.txt                                  |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Authors:                                                             |
14    |          Israel Ekpo <iekpo@php.net>                                 |
15    |          Omar Shaban <omars@php.net>                                 |
16    +----------------------------------------------------------------------+
17 */
18 
19 #include "php_solr.h"
20 
ZEND_EXTERN_MODULE_GLOBALS(json)21 ZEND_EXTERN_MODULE_GLOBALS(json)
22 
23 /** ************************************************************************ **/
24 /** FUNCTIONS FOR DECLARING CONSTANTS                                        **/
25 /** ************************************************************************ **/
26 
27 /* {{{ void solr_extension_register_constants(int type, int module_number) */
28 PHP_SOLR_API void solr_extension_register_constants(int type, int module_number)
29 {
30 	REGISTER_LONG_CONSTANT("SOLR_MAJOR_VERSION", PHP_SOLR_MAJOR_VERSION, CONST_CS | CONST_PERSISTENT);
31 	REGISTER_LONG_CONSTANT("SOLR_MINOR_VERSION", PHP_SOLR_MINOR_VERSION, CONST_CS | CONST_PERSISTENT);
32 	REGISTER_LONG_CONSTANT("SOLR_PATCH_VERSION", PHP_SOLR_PATCH_VERSION, CONST_CS | CONST_PERSISTENT);
33 
34 	REGISTER_STRING_CONSTANT("SOLR_EXTENSION_VERSION", PHP_SOLR_DOTTED_VERSION, CONST_CS | CONST_PERSISTENT);
35 }
36 /* }}} */
37 
38 /* {{{ void solr_document_register_class_constants(zend_class_entry * ce) */
solr_document_register_class_constants(zend_class_entry * ce)39 PHP_SOLR_API void solr_document_register_class_constants(zend_class_entry *ce)
40 {
41 	zend_declare_class_constant_long(ce, "SORT_DEFAULT", sizeof("SORT_DEFAULT")-1, SOLR_SORT_ASC);
42 	zend_declare_class_constant_long(ce, "SORT_ASC",     sizeof("SORT_ASC")-1, SOLR_SORT_ASC);
43 	zend_declare_class_constant_long(ce, "SORT_DESC",    sizeof("SORT_DESC")-1, SOLR_SORT_DESC);
44 
45 	zend_declare_class_constant_long(ce, "SORT_FIELD_NAME", sizeof("SORT_FIELD_NAME")-1, SOLR_SORT_FIELD_NAME);
46 	zend_declare_class_constant_long(ce, "SORT_FIELD_VALUE_COUNT", sizeof("SORT_FIELD_VALUE_COUNT")-1, SOLR_SORT_FIELD_VALUE_COUNT);
47 	zend_declare_class_constant_long(ce, "SORT_FIELD_BOOST_VALUE", sizeof("SORT_FIELD_BOOST_VALUE")-1, SOLR_SORT_FIELD_BOOST_VALUE);
48 }
49 /* }}} */
50 
solr_input_document_register_class_constants(zend_class_entry * ce)51 PHP_SOLR_API void solr_input_document_register_class_constants(zend_class_entry *ce)
52 {
53     solr_document_register_class_constants(ce);
54 
55     zend_declare_class_constant_long(ce, "UPDATE_MODIFIER_ADD", sizeof("UPDATE_MODIFIER_ADD")-1, SOLR_FIELD_VALUE_MOD_ADD);
56     zend_declare_class_constant_long(ce, "UPDATE_MODIFIER_SET", sizeof("UPDATE_MODIFIER_SET")-1, SOLR_FIELD_VALUE_MOD_SET);
57     zend_declare_class_constant_long(ce, "UPDATE_MODIFIER_INC", sizeof("UPDATE_MODIFIER_INC")-1, SOLR_FIELD_VALUE_MOD_INC);
58     zend_declare_class_constant_long(ce, "UPDATE_MODIFIER_REMOVE", sizeof("UPDATE_MODIFIER_REMOVE")-1, SOLR_FIELD_VALUE_MOD_REMOVE);
59     zend_declare_class_constant_long(ce, "UPDATE_MODIFIER_REMOVEREGEX", sizeof("UPDATE_MODIFIER_REMOVEREGEX")-1, SOLR_FIELD_VALUE_MOD_REMOVEREGEX);
60 
61     zend_declare_class_constant_long(ce, "VERSION_ASSERT_NONE", sizeof("VERSION_ASSERT_NONE")-1, SOLR_VERSION_ASSERT_NONE);
62     zend_declare_class_constant_long(ce, "VERSION_ASSERT_EXISTS", sizeof("VERSION_ASSERT_EXISTS")-1, SOLR_VERSION_ASSERT_EXISTS);
63     zend_declare_class_constant_long(ce, "VERSION_ASSERT_NOT_EXISTS", sizeof("VERSION_ASSERT_NOT_EXISTS")-1, SOLR_VERSION_ASSERT_NOT_EXISTS);
64 }
65 
66 /* {{{ void solr_collapse_function_register_class_constants(zend_class_entry * ce) */
solr_collapse_function_register_class_constants(zend_class_entry * ce)67 PHP_SOLR_API void solr_collapse_function_register_class_constants(zend_class_entry *ce)
68 {
69     zend_declare_class_constant_string(ce, "NULLPOLICY_IGNORE", sizeof("NULLPOLICY_IGNORE")-1, "ignore");
70     zend_declare_class_constant_string(ce, "NULLPOLICY_EXPAND", sizeof("NULLPOLICY_EXPAND")-1, "expand");
71     zend_declare_class_constant_string(ce, "NULLPOLICY_COLLAPSE", sizeof("NULLPOLICY_COLLAPSE")-1, "collapse");
72 }
73 /* }}} */
74 
75 /* {{{ void solr_client_register_class_constants(zend_class_entry *ce) */
solr_client_register_class_constants(zend_class_entry * ce)76 PHP_SOLR_API void solr_client_register_class_constants(zend_class_entry *ce)
77 {
78 	zend_declare_class_constant_long(ce, "SEARCH_SERVLET_TYPE",  sizeof("SEARCH_SERVLET_TYPE")-1, SOLR_SERVLET_TYPE_SEARCH);
79 	zend_declare_class_constant_long(ce, "UPDATE_SERVLET_TYPE",  sizeof("UPDATE_SERVLET_TYPE")-1, SOLR_SERVLET_TYPE_UPDATE);
80 	zend_declare_class_constant_long(ce, "THREADS_SERVLET_TYPE", sizeof("THREADS_SERVLET_TYPE")-1, SOLR_SERVLET_TYPE_THREADS);
81 	zend_declare_class_constant_long(ce, "PING_SERVLET_TYPE",    sizeof("PING_SERVLET_TYPE")-1, SOLR_SERVLET_TYPE_PING);
82 	zend_declare_class_constant_long(ce, "TERMS_SERVLET_TYPE",    sizeof("TERMS_SERVLET_TYPE")-1, SOLR_SERVLET_TYPE_TERMS);
83 	zend_declare_class_constant_long(ce, "SYSTEM_SERVLET_TYPE",    sizeof("SYSTEM_SERVLET_TYPE")-1, SOLR_SERVLET_TYPE_SYSTEM);
84 
85 	zend_declare_class_constant_string(ce, "DEFAULT_SEARCH_SERVLET",  sizeof("DEFAULT_SEARCH_SERVLET")-1, SOLR_DEFAULT_SEARCH_SERVLET);
86 	zend_declare_class_constant_string(ce, "DEFAULT_UPDATE_SERVLET",  sizeof("DEFAULT_UPDATE_SERVLET")-1, SOLR_DEFAULT_UPDATE_SERVLET);
87 	zend_declare_class_constant_string(ce, "DEFAULT_THREADS_SERVLET", sizeof("DEFAULT_THREADS_SERVLET")-1, SOLR_DEFAULT_THREADS_SERVLET);
88 	zend_declare_class_constant_string(ce, "DEFAULT_PING_SERVLET",    sizeof("DEFAULT_PING_SERVLET")-1, SOLR_DEFAULT_PING_SERVLET);
89 	zend_declare_class_constant_string(ce, "DEFAULT_TERMS_SERVLET",    sizeof("DEFAULT_TERMS_SERVLET")-1, SOLR_DEFAULT_TERMS_SERVLET);
90 	zend_declare_class_constant_string(ce, "DEFAULT_SYSTEM_SERVLET",    sizeof("DEFAULT_SYSTEM_SERVLET")-1, SOLR_DEFAULT_SYSTEM_SERVLET);
91 }
92 /* }}} */
93 
94 /* {{{ void solr_response_register_class_properties(zend_class_entry *ce) */
solr_response_register_class_properties(zend_class_entry * ce)95 PHP_SOLR_API void solr_response_register_class_properties(zend_class_entry *ce)
96 {
97 	zend_declare_property_long(ce, "http_status", sizeof("http_status")-1, 0L, ZEND_ACC_PROTECTED);
98 	zend_declare_property_long(ce, "parser_mode", sizeof("parser_mode")-1, 0L, ZEND_ACC_PROTECTED);
99 
100 	zend_declare_property_bool(ce, "success", sizeof("success")-1, 0L, ZEND_ACC_PROTECTED);
101 
102 	zend_declare_property_string(ce, "response_writer", sizeof("response_writer")-1, SOLR_SPACE_STRING, ZEND_ACC_PROTECTED);
103 	zend_declare_property_string(ce, "http_status_message", sizeof("http_status_message")-1, SOLR_SPACE_STRING, ZEND_ACC_PROTECTED);
104 	zend_declare_property_string(ce, "http_request_url", sizeof("http_request_url")-1, SOLR_SPACE_STRING, ZEND_ACC_PROTECTED);
105 	zend_declare_property_string(ce, "http_raw_request_headers", sizeof("http_raw_request_headers")-1, SOLR_SPACE_STRING, ZEND_ACC_PROTECTED);
106 	zend_declare_property_string(ce, "http_raw_request", sizeof("http_raw_request")-1, SOLR_SPACE_STRING, ZEND_ACC_PROTECTED);
107 	zend_declare_property_string(ce, "http_raw_response_headers", sizeof("http_raw_response_headers")-1, SOLR_SPACE_STRING, ZEND_ACC_PROTECTED);
108 	zend_declare_property_string(ce, "http_raw_response", sizeof("http_raw_response")-1, SOLR_SPACE_STRING, ZEND_ACC_PROTECTED);
109 	zend_declare_property_string(ce, "http_digested_response", sizeof("http_digested_response")-1, SOLR_SPACE_STRING, ZEND_ACC_PROTECTED);
110 }
111 /* }}} */
112 
113 /* {{{ void solr_exception_register_class_properties(zend_class_entry *ce) */
solr_exception_register_class_properties(zend_class_entry * ce)114 PHP_SOLR_API void solr_exception_register_class_properties(zend_class_entry *ce)
115 {
116 	zend_declare_property_long(ce, SOLR_SOURCELINE_NO_PROPERTY_NAME, sizeof(SOLR_SOURCELINE_NO_PROPERTY_NAME)-1, __LINE__, ZEND_ACC_PROTECTED);
117 	zend_declare_property_string(ce, SOLR_SOURCEFILE_PROPERTY_NAME, sizeof(SOLR_SOURCEFILE_PROPERTY_NAME)-1, __FILE__, ZEND_ACC_PROTECTED);
118 	zend_declare_property_string(ce, SOLR_ZIFNAME_PROPERTY_NAME, sizeof(SOLR_ZIFNAME_PROPERTY_NAME)-1, (char *) __func__, ZEND_ACC_PROTECTED);
119 }
120 /* }}} */
121 
122 /* {{{ void solr_response_register_class_constants(zend_class_entry *ce) */
solr_response_register_class_constants(zend_class_entry * ce)123 PHP_SOLR_API void solr_response_register_class_constants(zend_class_entry *ce)
124 {
125 	zend_declare_class_constant_long(ce, "PARSE_SOLR_OBJ",  sizeof("PARSE_SOLR_OBJ")-1, 0L);
126 	zend_declare_class_constant_long(ce, "PARSE_SOLR_DOC",  sizeof("PARSE_SOLR_DOC")-1, 1L);
127 }
128 /* }}} */
129 
130 /* {{{ void solr_query_register_class_constants(zend_class_entry *ce) */
solr_query_register_class_constants(zend_class_entry * ce)131 PHP_SOLR_API void solr_query_register_class_constants(zend_class_entry *ce)
132 {
133 	zend_declare_class_constant_long(ce, "ORDER_ASC",  sizeof("ORDER_ASC")-1, SOLR_SORT_DIR_ASC);
134 	zend_declare_class_constant_long(ce, "ORDER_DESC",  sizeof("ORDER_DESC")-1, SOLR_SORT_DIR_DESC);
135 
136 	zend_declare_class_constant_long(ce, "FACET_SORT_INDEX", sizeof("FACET_SORT_INDEX")-1, 0L);
137 	zend_declare_class_constant_long(ce, "FACET_SORT_COUNT", sizeof("FACET_SORT_COUNT")-1, 1L);
138 
139 	zend_declare_class_constant_long(ce, "TERMS_SORT_INDEX", sizeof("TERMS_SORT_INDEX")-1, 0L);
140 	zend_declare_class_constant_long(ce, "TERMS_SORT_COUNT", sizeof("TERMS_SORT_COUNT")-1, 1L);
141 }
142 /* }}} */
143 
solr_extract_register_class_constants(zend_class_entry * ce)144 PHP_SOLR_API void solr_extract_register_class_constants(zend_class_entry *ce)
145 {
146     zend_declare_class_constant_string(ce, "CAPTURE_ELEMENTS", sizeof("CAPTURE_ELEMENTS")-1, "capture");
147     zend_declare_class_constant_string(ce, "CAPTURE_ATTRIBUTES", sizeof("CAPTURE_ATTRIBUTES")-1, "captureAttr");
148     zend_declare_class_constant_string(ce, "COMMIT_WITHIN", sizeof("COMMIT_WITHIN")-1,  "commitWithin");
149     zend_declare_class_constant_string(ce, "DATE_FORMATS", sizeof("DATE_FORMATS")-1,    "date.formats");
150     zend_declare_class_constant_string(ce, "DEFAULT_FIELD", sizeof("DEFAULT_FIELD")-1,  "defaultField");
151     zend_declare_class_constant_string(ce, "EXTRACT_ONLY", sizeof("EXTRACT_ONLY")-1,    "extractOnly");
152     zend_declare_class_constant_string(ce, "EXTRACT_FORMAT", sizeof("EXTRACT_FORMAT")-1,"extractFormat");
153     zend_declare_class_constant_string(ce, "IGNORE_TIKA_EXCEPTION", sizeof("IGNORE_TIKA_EXCEPTION")-1, "ignoreTikaException");
154     zend_declare_class_constant_string(ce, "LITERALS_OVERRIDE", sizeof("LITERALS_OVERRIDE")-1, "literalsOverride");
155     zend_declare_class_constant_string(ce, "LOWERNAMES", sizeof("LOWERNAMES")-1, "lowernames");
156     zend_declare_class_constant_string(ce, "MULTIPART_UPLOAD_LIMIT", sizeof("MULTIPART_UPLOAD_LIMIT")-1, "multipartUploadLimitInKB");
157     zend_declare_class_constant_string(ce, "PASSWORD_MAP_FILE", sizeof("PASSWORD_MAP_FILE")-1, "passwordsFile");
158     zend_declare_class_constant_string(ce, "RESOURCE_NAME", sizeof("RESOURCE_NAME")-1, "resource.name");
159     zend_declare_class_constant_string(ce, "RESOURCE_PASSWORD", sizeof("RESOURCE_PASSWORD")-1, "resource.password");
160     zend_declare_class_constant_string(ce, "TIKE_CONFIG", sizeof("TIKE_CONFIG")-1, "tika.config");
161     zend_declare_class_constant_string(ce, "UNKNOWN_FIELD_PREFIX", sizeof("UNKNOWN_FIELD_PREFIX")-1, "uprefix");
162     zend_declare_class_constant_string(ce, "XPATH_EXPRESSION", sizeof("XPATH_EXPRESSION")-1, "xpath");
163     zend_declare_class_constant_string(ce, "FIELD_MAPPING_PREFIX", sizeof("FIELD_MAPPING_PREFIX")-1, "fmap.");
164     zend_declare_class_constant_string(ce, "FIELD_BOOST_PREFIX", sizeof("FIELD_BOOST_PREFIX")-1, "boost.");
165     zend_declare_class_constant_string(ce, "LITERALS_PREFIX", sizeof("LITERALS_PREFIX")-1, "literal.");
166 }
167 
168 /** ************************************************************************ **/
169 /** UTILITY FUNCTIONS                                                        **/
170 /** ************************************************************************ **/
171 
172 /* {{{ int solr_hashtable_get_new_index(HashTable *ht)
173 	Retrieves a unique index for this HashTable */
solr_hashtable_get_new_index(HashTable * ht)174 PHP_SOLR_API int solr_hashtable_get_new_index(HashTable *ht)
175 {
176 	int new_index = SOLR_GET_RANDOM_NUMBER();
177 
178 	/* If the key already exists in the HashTable, create another one. */
179 	while(zend_hash_index_exists(ht, new_index)) {
180 
181 		new_index = SOLR_GET_RANDOM_NUMBER();
182 	}
183 
184 	return new_index;
185 }
186 /* }}} */
187 
188 /* {{{ static inline int solr_fetch_document_entry(zval *objptr, solr_document_t **doc_entry)
189 	Retrieves a Document from the HashTable */
190 #if PHP_VERSION_ID < 80000
solr_fetch_document_entry(zval * objptr,solr_document_t ** doc_entry)191 PHP_SOLR_API int solr_fetch_document_entry(zval *objptr, solr_document_t **doc_entry)
192 {
193     zval *rv = NULL;
194 	zval *id = zend_read_property(Z_OBJCE_P(objptr), objptr, SOLR_INDEX_PROPERTY_NAME, sizeof(SOLR_INDEX_PROPERTY_NAME) - 1, 1, rv);
195 #else
196 PHP_SOLR_API int solr_fetch_document_entry(zend_object *objptr, solr_document_t **doc_entry)
197 {
198     zval *rv = NULL;
199 	zval *id = zend_read_property(objptr->ce, objptr, SOLR_INDEX_PROPERTY_NAME, sizeof(SOLR_INDEX_PROPERTY_NAME) - 1, 1, rv);
200 #endif
201 
202 	/* Retrieving the value of the document index from the zval */
203 	long int document_index = Z_LVAL_P(id);
204 
205 	*doc_entry = NULL;
206 
207 	/* Retrieve the doc_entry from the HashTable */
208 	if ((*doc_entry = (solr_document_t *)zend_hash_index_find_ptr(SOLR_GLOBAL(documents), document_index)) == NULL) {
209 
210 		php_error_docref(NULL, E_WARNING, "Invalid Document Index %ld. HashTable index does not exist.", document_index);
211 
212 		php_error_docref(NULL, E_WARNING, SOLR_ERROR_1008_MSG, SOLR_FILE_LINE_FUNC);
213 
214 		return FAILURE;
215 	}
216 
217 	return SUCCESS;
218 }
219 /* }}} */
220 
221 /* {{{ PHP_SOLR_API int solr_fetch_client_entry(zval *objptr, solr_client_t **solr_client) */
222 PHP_SOLR_API int solr_fetch_client_entry(zval *objptr, solr_client_t **solr_client)
223 {
224     zval rv;
225 	zval *id = zend_read_property(solr_ce_SolrClient, OBJ_FOR_PROP(objptr), SOLR_INDEX_PROPERTY_NAME, sizeof(SOLR_INDEX_PROPERTY_NAME) - 1, 1, &rv);
226 
227 	/* Retrieving the value of the client index from the zval */
228 	long int client_index = Z_LVAL_P(id);
229 
230 	*solr_client = NULL;
231 
232 	/* Retrieve the doc_entry from the HashTable */
233 	if ((*solr_client = zend_hash_index_find_ptr(SOLR_GLOBAL(clients), client_index)) == NULL) {
234 
235 		php_error_docref(NULL, E_WARNING, "Invalid SolrClient Index %ld. HashTable index does not exist.", client_index);
236 
237 		php_error_docref(NULL, E_WARNING, SOLR_ERROR_1008_MSG, SOLR_FILE_LINE_FUNC);
238 
239 		return FAILURE;
240 	}
241 
242 	return SUCCESS;
243 }
244 /* }}} */
245 
246 /* {{{ PHP_SOLR_API int solr_fetch_params_entry(zval *objptr, solr_params_t **solr_params) */
247 PHP_SOLR_API int solr_fetch_params_entry(zval *objptr, solr_params_t **solr_params)
248 {
249     zval rv;
250 	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);
251 
252 	long int params_index = Z_LVAL_P(id);
253 
254 	*solr_params = NULL;
255 
256 	if ((*solr_params = zend_hash_index_find_ptr(SOLR_GLOBAL(params), params_index)) == NULL) {
257 
258 		php_error_docref(NULL, E_WARNING, "Invalid SolrParams Index %ld. HashTable index does not exist.", params_index);
259 
260 		php_error_docref(NULL, E_WARNING, SOLR_ERROR_1008_MSG, SOLR_FILE_LINE_FUNC);
261 
262 		return FAILURE;
263 	}
264 
265 	return SUCCESS;
266 }
267 /* }}} */
268 
269 PHP_SOLR_API int solr_fetch_function_entry(zval *objptr, solr_function_t **solr_function)
270 {
271     zval rv;
272     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);
273 
274     long int params_index = Z_LVAL_P(id);
275 
276     *solr_function = NULL;
277 
278     if ((*solr_function = zend_hash_index_find_ptr(SOLR_GLOBAL(functions), params_index)) == NULL) {
279         php_error_docref(NULL, E_WARNING, "Invalid solr_function Index %ld. HashTable index does not exist.", params_index);
280 
281         php_error_docref(NULL, E_WARNING, SOLR_ERROR_1008_MSG, SOLR_FILE_LINE_FUNC);
282 
283         return FAILURE;
284     }
285 
286     return SUCCESS;
287 }
288 
289 /* {{{ PHP_SOLR_API void solr_destroy_function(zval *solr_function) */
290 PHP_SOLR_API void solr_destroy_function(zval *solr_function)
291 {
292     solr_function_t *function = (solr_function_t *) Z_PTR_P(solr_function);
293 
294     zend_hash_destroy(function->params);
295 
296     pefree(function->params, SOLR_FUNCTIONS_PERSISTENT);
297 
298 #ifdef PHP_7
299     pefree(function, SOLR_FUNCTIONS_PERSISTENT);
300 #endif
301 }
302 /* }}} */
303 
304 /* {{{ PHP_SOLR_API xmlDocPtr solr_xml_create_xml_doc(const xmlChar *root_node_name, xmlNode **root_node_ptr) */
305 PHP_SOLR_API xmlDocPtr solr_xml_create_xml_doc(const xmlChar *root_node_name, xmlNode **root_node_ptr)
306 {
307 	xmlNs *ns = NULL;
308 
309 	xmlDoc *doc_ptr = xmlNewDoc((xmlChar *) "1.0");
310 
311 	xmlNode *root_node = xmlNewNode(ns, root_node_name);
312 
313 	xmlDocSetRootElement(doc_ptr, root_node);
314 
315 	if (root_node_ptr)
316 	{
317 		*root_node_ptr = root_node;
318 	}
319 
320 	return doc_ptr;
321 }
322 /* }}} */
323 
324 /**
325  * escapes strings with characters that are part of the Lucene query syntax
326  *
327  * @sbuilder is a solr_string_t pointer used to store the escape char sequence
328  * @unescaped is the unescaped string. It must be null terminated
329  * @unescaped_length is the original length of the unescaped_string
330  */
331 /* {{{ PHP_SOLR_API void solr_escape_query_chars(solr_string_t *sbuilder, solr_char_t *unescaped, long int unescaped_length) */
332 PHP_SOLR_API void solr_escape_query_chars(solr_string_t *sbuilder, solr_char_t *unescaped, long int unescaped_length)
333 {
334 	register int i = 0;
335 
336 	/**
337 	 * Lucene supports escaping special characters that are part of the query syntax.
338 	 *
339 	 * The current list special characters are
340 	 * + - && || ! ( ) { } [ ] ^ " ~ * ? : \ /
341 	 *
342 	 * These characters are part of the query syntax and must be escaped
343 	 */
344 	for (i = 0; i < unescaped_length; i++) {
345 
346 enter_switchboard :
347 
348 		switch(unescaped[i])
349 		{
350 			case '\\' :
351 			case '+'  :
352 			case '-'  :
353 			case '!'  :
354 			case '('  :
355 			case ')'  :
356 			case ':'  :
357 			case '/'  :
358 
359 			case '^'  :
360 			case '['  :
361 			case ']'  :
362 			case '"'  :
363 			case '{'  :
364 			case '}'  :
365 			case '~'  :
366 
367 			case '*'  :
368 			case '?'  :
369 			case ';'  :
370 			{
371 				solr_string_appendc(sbuilder, '\\');
372 			}
373 			break;
374 
375 			case '|'  : /* || */
376 			{
377 				if ('|' == unescaped[i+1])
378 				{
379 					solr_string_appendc(sbuilder, '\\');
380 
381 					solr_string_append_const(sbuilder, "||");
382 
383 					i += 2;
384 
385 					goto enter_switchboard;
386 				}
387 			}
388 			break;
389 
390 			case '&'  : /* && */
391 			{
392 				if ('&' == unescaped[i+1])
393 				{
394 					solr_string_appendc(sbuilder, '\\');
395 
396 					solr_string_append_const(sbuilder, "&&");
397 
398 					i += 2;
399 
400 					goto enter_switchboard;
401 				}
402 			}
403 			break;
404 
405 			default : /* The current character is not a special character */
406 			{
407 				/* Do nothing. Just append the character as is */
408 			}
409 
410 		} /* END switch(unescaped[i]) */
411 
412 		solr_string_appendc(sbuilder, unescaped[i]);
413 
414 	} /* END for (i = 0; i < unescaped_length; i++) { */
415 }
416 /* }}} */
417 
418 /******************************************************************************/
419 /* SOLR XML RESPONSE DIGEST DATA TYPES AND FUNCTIONS                          */
420 /******************************************************************************/
421 
422 /* {{{ solr_doc_encode_t, solr_php_encode_t, solr_encoding_type_t, solr_php_encode_func_t, solr_document_field_encode_func_t */
423 typedef enum
424 {
425 	SOLR_DOC_ENCODE_START  = 0,
426 	SOLR_DOC_ENCODE_FIELDS = 1,
427 	SOLR_DOC_ENCODE_FIELD  = 2,
428 	SOLR_DOC_ENCODE_END
429 
430 } solr_doc_encode_t;
431 
432 typedef enum
433 {
434 	SOLR_ENCODE_START	= 0,
435 	SOLR_ENCODE_NULL	= 1,
436 	SOLR_ENCODE_BOOL	= 2,
437 	SOLR_ENCODE_INT		= 3,
438 	SOLR_ENCODE_FLOAT	= 4,
439 	SOLR_ENCODE_STRING  = 5,
440 	SOLR_ENCODE_ARRAY  	= 6,
441 	SOLR_ENCODE_OBJECT  = 7,
442 	SOLR_ENCODE_DOC		= 8,
443 	SOLR_ENCODE_RESULT	= 9,
444 	SOLR_ENCODE_END
445 } solr_php_encode_t;
446 
447 typedef enum
448 {
449 	SOLR_ENCODE_STANDALONE 		= 0,
450 	SOLR_ENCODE_OBJECT_PROPERTY = 1,
451 	SOLR_ENCODE_ARRAY_KEY   	= 2,
452 	SOLR_ENCODE_ARRAY_INDEX     = 3
453 } solr_encoding_type_t;
454 
455 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);
456 
457 typedef void (*solr_document_field_encode_func_t)(const xmlNode *node, xmlNode *field);
458 /* }}} */
459 
460 /* {{{ Macros for XML transcoding */
461 /* Serializes the current XML node */
462 #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))
463 
464 #define solr_write_object_closer(__buf) solr_string_append_const((__buf), "}")
465 
466 #define solr_write_array_closer(__buf) solr_string_append_const((__buf), "}")
467 
468 #define solr_write_root_object_closer(__buf) solr_string_append_const((__buf), "}")
469 /* }}} */
470 
471 /* {{{ static void solr_encode_* prototypes */
472 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);
473 
474 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);
475 
476 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);
477 
478 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);
479 
480 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);
481 
482 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);
483 
484 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);
485 
486 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);
487 
488 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);
489 
490 static void solr_encode_document_field_simple(const xmlNode *fieldNode, xmlNode *field);
491 
492 static void solr_encode_document_field_complex(const xmlNode *fieldNode, xmlNode *field);
493 /* }}} */
494 
495 /* {{{ global variables solr_encoder_functions[], solr_document_field_encoders[] */
496 static solr_php_encode_func_t solr_encoder_functions[] = {
497 	solr_encode_string,
498 	solr_encode_null,
499 	solr_encode_bool,
500 	solr_encode_int,
501 	solr_encode_float,
502 	solr_encode_string,
503 	solr_encode_array,
504 	solr_encode_object,
505 	solr_encode_document,
506 	solr_encode_result,
507 	NULL
508 };
509 
510 static solr_document_field_encode_func_t solr_document_field_encoders[] = {
511 	solr_encode_document_field_simple, /* maps to SOLR_SIMPLE_FIELD */
512 	solr_encode_document_field_complex, /* maps to SOLR_COMPLEX_FIELD */
513 	NULL
514 };
515 /* }}} */
516 
517 /* {{{ Constants and Macros for handling node types */
518 #define SOLR_SIMPLE_FIELD 0
519 #define SOLR_COMPLEX_FIELD 1
520 
521 #define solr_xml_field_node_type(node) (xmlStrEqual((node)->name, (xmlChar *)"arr")? SOLR_COMPLEX_FIELD : SOLR_SIMPLE_FIELD)
522 
523 #define solr_encode_document_field(field_in, field_out) solr_document_field_encoders[solr_xml_field_node_type((field_in))]((field_in), (field_out))
524 /* }}} */
525 
526 /* Used to figure out now many properties or elements there are in an object or an array */
527 /* {{{ static inline int solr_get_node_size(const xmlNode *data_node) */
528 static inline int solr_get_node_size(const xmlNode *data_node)
529 {
530 	register int size = 0;
531 
532 	xmlNode *curr_node = data_node->children;
533 
534 	while(curr_node != NULL)
535 	{
536 		if (XML_ELEMENT_NODE == curr_node->type)
537 		{
538 			size++;
539 		}
540 
541 		curr_node = curr_node->next;
542 	}
543 
544 	return size;
545 }
546 /* }}} */
547 
548 /* {{{ static inline int solr_get_xml_type(xmlNode *node) */
549 static inline int solr_get_xml_type(xmlNode *node)
550 {
551 	solr_char_t *node_name = (solr_char_t *) node->name;
552 
553 	if (!node_name)
554 	{
555 		return SOLR_ENCODE_STRING;
556 	}
557 
558 	if (!strcmp(node_name, "str")) {
559 
560 		return SOLR_ENCODE_STRING;
561 
562 	} else if (!strcmp(node_name, "int") || !strcmp(node_name, "long") || !strcmp(node_name, "short") || !strcmp(node_name, "byte")) {
563 
564 		return SOLR_ENCODE_INT;
565 
566 	} else if (!strcmp(node_name, "double") || !strcmp(node_name, "float")) {
567 
568 		return SOLR_ENCODE_FLOAT;
569 
570 	} else if (!strcmp(node_name, "lst")) {
571 
572 		return SOLR_ENCODE_OBJECT;
573 
574 	} else if (!strcmp(node_name, "arr")) {
575 
576 		return SOLR_ENCODE_ARRAY;
577 
578 	} else if (!strcmp(node_name, "bool")) {
579 
580 		return SOLR_ENCODE_BOOL;
581 
582 	} else if (!strcmp(node_name, "null")) {
583 
584 		return SOLR_ENCODE_NULL;
585 
586 	} else if (!strcmp(node_name, "result")) {
587 
588 		return SOLR_ENCODE_RESULT;
589 	}else if (!strcmp(node_name, "doc")) {
590 
591 	    return SOLR_ENCODE_OBJECT;
592 	} else {
593 
594 		return SOLR_ENCODE_STRING;
595 	}
596 }
597 /* }}} */
598 
599 /* {{{ static inline void solr_write_variable_opener(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index) */
600 static inline void solr_write_variable_opener(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index)
601 {
602 	switch(enc_type)
603 	{
604 		case SOLR_ENCODE_OBJECT_PROPERTY : /* fall through */
605 		case SOLR_ENCODE_ARRAY_KEY :
606 		{
607 			solr_char_t *object_name = "_undefined_property_name";
608 
609 			xmlAttr *name_attr = node->properties; /* get the contents of the name attribute */
610 
611 			if (name_attr)
612 			{
613 				object_name = (solr_char_t *) solr_xml_get_node_contents(name_attr);
614 			}
615 
616 			solr_string_append_const(buffer, "s:");
617 
618 			solr_string_append_long(buffer, strlen(object_name));
619 
620 			solr_string_append_const(buffer, ":\"");
621 
622 			solr_string_appends(buffer, object_name, strlen(object_name));
623 
624 			solr_string_append_const(buffer, "\";");
625 		}
626 		break;
627 
628 		case SOLR_ENCODE_ARRAY_INDEX :
629 		{
630 			solr_string_append_const(buffer, "i:");
631 
632 			solr_string_append_long(buffer, array_index);
633 
634 			solr_string_appendc(buffer, ';');
635 		}
636 		break;
637 
638 		default :
639 		{
640 			/* do nothing */
641 		}
642 		break;
643 	}
644 }
645 /* }}} */
646 
647 /* {{{ static void solr_write_object_opener(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index) */
648 static void solr_write_object_opener(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index)
649 {
650 	int size = solr_get_node_size(node);
651 
652 	solr_write_variable_opener(node, buffer, enc_type, array_index);
653 
654 	solr_string_append_const(buffer, "O:10:\"SolrObject\":");
655 
656 	solr_string_append_long(buffer, size);
657 
658 	solr_string_append_const(buffer, ":{");
659 }
660 /* }}} */
661 
662 /* {{{ 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) */
663 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)
664 {
665 	solr_write_variable_opener(node, buffer, enc_type, array_index);
666 
667 	solr_string_append_const(buffer, "C:12:\"SolrDocument\":");
668 
669 	solr_string_append_long(buffer, size);
670 
671 	solr_string_append_const(buffer, ":{");
672 }
673 /* }}} */
674 
675 /* {{{ static void solr_write_array_opener(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index) */
676 static void solr_write_array_opener(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index)
677 {
678 	int size = solr_get_node_size(node);
679 
680 	solr_write_variable_opener(node, buffer, enc_type, array_index);
681 
682 	solr_string_append_const(buffer, "a:");
683 
684 	solr_string_append_long(buffer, size);
685 
686 	solr_string_append_const(buffer, ":{");
687 }
688 /* }}} */
689 
690 static void solr_serialize_solr_document(const xmlNode *node, solr_string_t *dest);
691 static void solr_encode_solr_document_children(const xmlNode *node, xmlNode* builder_node, int child_docs_found);
692 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);
693 
694 static void solr_serialize_solr_document(const xmlNode *node, solr_string_t *dest)
695 {
696     xmlChar *doc_txt_buffer = NULL;
697     int doc_txt_len = 0;
698     xmlNode *solr_document_node = NULL;
699     xmlDoc *doc_ptr = solr_xml_create_xml_doc((xmlChar *) "solr_document", &solr_document_node);
700     xmlNode *fields_node = xmlNewChild(solr_document_node, NULL, (xmlChar *) "fields", NULL);
701     xmlNode *curr_node = node->children;
702     int format = 1;
703     int child_docs_found = 0;
704 
705     while(curr_node != NULL)
706     {
707         if (XML_ELEMENT_NODE == curr_node->type)
708         {
709             if (strcmp((const char *)curr_node->name, "doc") == 0)
710             {
711                 child_docs_found++;
712             } else {
713                 xmlNode *field = xmlNewChild(fields_node, NULL, (xmlChar *)"field", NULL);
714                 solr_encode_document_field(curr_node, field);
715             }
716         }
717 
718         curr_node = curr_node->next;
719     }
720 
721     if (child_docs_found > 0)
722     {
723         solr_encode_solr_document_children(node, solr_document_node, child_docs_found);
724     }
725 
726     /* We have written all the fields to the document */
727     /* Dumping the document from memory to the buffer */
728     xmlDocDumpFormatMemoryEnc(doc_ptr, &doc_txt_buffer, &doc_txt_len, "UTF-8", format);
729 
730     solr_string_appends_ex(dest, (solr_char_t *)doc_txt_buffer, doc_txt_len);
731 
732     xmlFreeDoc(doc_ptr);
733     xmlFree(doc_txt_buffer);
734 }
735 
736 /* {{{ static void solr_encode_document_children(const xmlNode *node, solr_string_t* buffer, int child_docs_found, long int parse_mode)
737    encodes the doc/doc child/nested documents */
738 static void solr_encode_solr_document_children(const xmlNode *node, xmlNode* builder_node, int child_docs_found)
739 {
740     int current_index = 0;
741     xmlXPathContext *xpathctxt = NULL;
742     const xmlChar *xpath_expression = (xmlChar *) "child::doc";
743     xmlXPathObject *xpathObj = NULL;
744     xmlNodeSet *result = NULL;
745     xmlNode *child_docs_node = NULL;
746 
747     xpathctxt = xmlXPathNewContext(node->doc);
748     xpathctxt->node = (xmlNodePtr) node;
749     xpathObj = xmlXPathEval(xpath_expression, xpathctxt);
750     result = xpathObj->nodesetval;
751     child_docs_found = result->nodeNr;
752 
753     child_docs_node = xmlNewChild(builder_node, NULL, (xmlChar *)"child_docs", NULL);
754 
755     for (current_index=0; current_index < child_docs_found; current_index++)
756     {
757         zend_string *encoded_str = NULL;
758 
759         solr_string_t tmp_buffer;
760         solr_string_t tmp_s_buffer;
761         memset(&tmp_buffer, 0, sizeof(solr_string_t));
762         memset(&tmp_s_buffer, 0, sizeof(solr_string_t));
763 
764         solr_serialize_solr_document(result->nodeTab[current_index], &tmp_buffer);
765 
766         solr_string_append_const(&tmp_s_buffer, "C:12:\"SolrDocument\":");
767 
768         solr_string_append_long(&tmp_s_buffer, tmp_buffer.len);
769 
770         solr_string_append_const(&tmp_s_buffer, ":{");
771 
772         solr_string_appends_ex(&tmp_s_buffer, tmp_buffer.str, tmp_buffer.len);
773         solr_write_object_closer(&tmp_s_buffer);
774 
775         encoded_str = php_base64_encode((const unsigned char*)tmp_s_buffer.str, tmp_s_buffer.len);
776         xmlNewChild(child_docs_node, NULL, (const xmlChar *) "dochash", (xmlChar *)encoded_str->val);
777         solr_string_free_ex(&tmp_buffer);
778         solr_string_free_ex(&tmp_s_buffer);
779         zend_string_free(encoded_str);
780     }
781 }
782 /* }}} */
783 
784 /**
785  *
786  * The @enc_type parameter must be SOLR_ENCODE_ARRAY_INDEX
787  */
788 /* {{{ 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) */
789 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)
790 {
791     solr_string_t doc_serialized_buffer;
792     memset(&doc_serialized_buffer, 0, sizeof(solr_string_t));
793 
794     solr_serialize_solr_document(node, &doc_serialized_buffer);
795 
796     solr_write_solr_document_opener(NULL, buffer, enc_type, array_index, doc_serialized_buffer.len);
797 
798     solr_string_appends(buffer, (char *) doc_serialized_buffer.str, doc_serialized_buffer.len);
799 
800     solr_write_object_closer(buffer);
801     solr_string_free(&doc_serialized_buffer);
802 }
803 /* }}} */
804 
805 
806 /* {{{ static void solr_write_object_opener(const xmlNode *node, solr_string_t *buffer, solr_encoding_type_t enc_type, long int array_index) */
807 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)
808 {
809     int size = solr_get_node_size(node) - num_child_docs + 1;
810 
811     solr_write_variable_opener(node, buffer, enc_type, array_index);
812 
813     solr_string_append_const(buffer, "O:10:\"SolrObject\":");
814 
815     solr_string_append_long(buffer, size);
816 
817     solr_string_append_const(buffer, ":{");
818 }
819 /* }}} */
820 
821 /* {{{ static void solr_encode_document_children(const xmlNode *node, solr_string_t* buffer, int child_docs_found, long int parse_mode)
822    encodes the doc/doc child/nested documents ONLY FOR SolrObject */
823 static void solr_encode_document_children(const xmlNode *node, solr_string_t* buffer, int child_docs_found, long int parse_mode)
824 {
825     int current_index = 0;
826     xmlXPathContext *xpathctxt = NULL;
827     const xmlChar *xpath_expression = (xmlChar *) "child::doc";
828     xmlXPathObject *xpathObj = NULL;
829     xmlNodeSet *result = NULL;
830 
831     solr_php_encode_func_t document_encoder_functions[] = {
832             solr_encode_document,
833             solr_encode_solr_document,
834             NULL
835     };
836 
837     solr_string_append_const(buffer, "s:");
838     solr_string_append_long(buffer, sizeof("_childDocuments_")-1);
839     solr_string_append_const(buffer, ":\"");
840     solr_string_appends(buffer, "_childDocuments_", sizeof("_childDocuments_")-1);
841     solr_string_append_const(buffer, "\";");
842     solr_string_append_const(buffer, "a:");
843 
844     solr_string_append_long(buffer, child_docs_found);
845 
846     solr_string_append_const(buffer, ":{");
847 
848     xpathctxt = xmlXPathNewContext(node->doc);
849     xpathctxt->node = (xmlNodePtr) node;
850     xpathObj = xmlXPathEval(xpath_expression, xpathctxt);
851     result = xpathObj->nodesetval;
852     child_docs_found = result->nodeNr;
853 
854     for (current_index=0; current_index < child_docs_found; current_index++)
855     {
856         document_encoder_functions[parse_mode](result->nodeTab[current_index], buffer, SOLR_ENCODE_ARRAY_INDEX, current_index, parse_mode);
857     }
858     solr_write_array_closer(buffer);
859 }
860 /* }}} */
861 
862 /* {{{ 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)
863    encodes/serializes the <doc> element result/doc */
864 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)
865 {
866 	xmlNode *curr_node = NULL;
867 
868 	int child_docs_found = 0;
869 	solr_string_t inner_buffer;
870 	memset(&inner_buffer, 0, sizeof(solr_string_t));
871 
872 	curr_node = node->children;
873 
874 	while(curr_node != NULL)
875 	{
876 		if (XML_ELEMENT_NODE == curr_node->type)
877 		{
878 		    if (strcmp((const char*) curr_node->name, "doc") == 0)
879 		    {
880 		        /* skip doc/doc elements to be processed later */
881 		        child_docs_found++;
882 		    } else {
883 		        solr_encode_xml_node(curr_node, &inner_buffer, SOLR_ENCODE_OBJECT_PROPERTY, 0L, parse_mode);
884 		    }
885 		}
886 		curr_node = curr_node->next;
887 	}
888 
889 	if (child_docs_found > 0){
890 	    solr_encode_document_children(node, &inner_buffer, child_docs_found, parse_mode);
891 	    /**
892 	     * write and calculate proper object opener
893 	     * because the object number of properties depends on whether there are child documents involved
894 	     */
895 	    solr_write_object_opener_child_doc(node, child_docs_found, buffer, enc_type, array_index);
896 	} else {
897 	    solr_write_object_opener(node, buffer, enc_type, array_index);
898 	}
899 
900 	solr_string_appends_ex(buffer, inner_buffer.str, inner_buffer.len);
901 	solr_write_object_closer(buffer);
902 
903 	solr_string_free_ex(&inner_buffer);
904 }
905 /* }}} */
906 
907 /**
908  * Handles simple data types like strings, integers, booleans etc.
909  */
910 /* {{{ static void solr_encode_document_field_simple(const xmlNode *fieldNode, xmlNode *field) */
911 static void solr_encode_document_field_simple(const xmlNode *fieldNode, xmlNode *field)
912 {
913 	xmlChar *fieldname = solr_xml_get_node_contents(fieldNode->properties);
914 
915 	xmlChar *field_value = xmlEncodeEntitiesReentrant(fieldNode->doc, solr_xml_get_node_contents(fieldNode));
916 
917 	xmlNewChild(field, NULL, (xmlChar *) "field_value", field_value);
918 
919 	xmlNewProp(field, (xmlChar *) "name", fieldname);
920 
921 	xmlFree(field_value);
922 }
923 /* }}} */
924 
925 /* Handles complex data types like arrays */
926 /* {{{ static void solr_encode_document_field_complex(const xmlNode *fieldNode, xmlNode *field) */
927 static void solr_encode_document_field_complex(const xmlNode *fieldNode, xmlNode *field)
928 {
929 	xmlChar *fieldname = solr_xml_get_node_contents(fieldNode->properties);
930 
931 	xmlNode *current_value = fieldNode->children;
932 
933 	while(current_value != NULL)
934 	{
935 		if (current_value->type == XML_ELEMENT_NODE)
936 		{
937 			xmlChar *field_value = xmlEncodeEntitiesReentrant(fieldNode->doc, solr_xml_get_node_contents(current_value));
938 
939 			xmlNewChild(field, NULL, (xmlChar *) "field_value", field_value);
940 
941 			xmlFree(field_value);
942 		}
943 
944 		current_value = current_value->next;
945 	}
946 
947 	xmlNewProp(field, (xmlChar *) "name", fieldname);
948 }
949 /* }}} */
950 
951 /* {{{ 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) */
952 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)
953 {
954 	xmlAttr *properties = node->properties;
955 
956 	solr_char_t *object_name = (solr_char_t *) node->name;
957 	solr_char_t *num_found   = NULL;
958 	solr_char_t *start       = NULL;
959     solr_char_t *max_score   = NULL;
960 
961 	solr_php_encode_func_t document_encoder_functions[] = {
962 		solr_encode_document,
963 		solr_encode_solr_document,
964 		NULL
965 	};
966 
967 	xmlAttr *curr_prop = properties;
968 	xmlXPathContext *xpathctxt = NULL;
969 	const xmlChar *xpath_expression = (xmlChar *) "child::doc";
970 	xmlXPathObject *xpathObj = NULL;
971 	xmlNodeSet *result = NULL;
972 	long int document_count = 0;
973 
974 	while(curr_prop != NULL)
975 	{
976 		if (solr_xml_match_node(curr_prop, "numFound"))
977 		{
978 			num_found = (solr_char_t *) solr_xml_get_node_contents(curr_prop);
979 		}
980 
981 		if (solr_xml_match_node(curr_prop, "start"))
982 		{
983 			start = (solr_char_t *) solr_xml_get_node_contents(curr_prop);
984 		}
985 
986 		if (solr_xml_match_node(curr_prop, "name"))
987 		{
988 			object_name = (solr_char_t *) solr_xml_get_node_contents(curr_prop);
989 		}
990 
991         if (solr_xml_match_node(curr_prop, "maxScore"))
992         {
993             max_score = (solr_char_t *) solr_xml_get_node_contents(curr_prop);
994         }
995 
996 		curr_prop = curr_prop->next;
997 	}
998 
999 	xpathctxt = xmlXPathNewContext(node->doc);
1000 	xpathctxt->node = (xmlNodePtr) node;
1001 	xpathObj = xmlXPathEval(xpath_expression, xpathctxt);
1002 	result = xpathObj->nodesetval;
1003 	document_count = result->nodeNr;
1004 
1005 	solr_string_append_const(buffer, "s:");
1006 	solr_string_append_long(buffer, strlen(object_name));
1007 	solr_string_append_const(buffer, ":\"");
1008 	solr_string_appends(buffer, object_name, strlen(object_name));
1009 
1010 	solr_string_append_const(buffer, "\";");
1011 	solr_string_append_const(buffer, "O:10:\"SolrObject\":");
1012 	if (max_score) {
1013 	    solr_string_append_long(buffer, 4); /* numFound, start, docs, maxScore properties */
1014 	} else {
1015 	    solr_string_append_long(buffer, 3); /* numFound, start, docs properties */
1016 	}
1017 
1018 	solr_string_append_const(buffer, ":{"); /* Object Opener for response */
1019 
1020 	/* Writing the numFound property */
1021 	solr_string_append_const(buffer, "s:");
1022 	solr_string_append_long(buffer, sizeof("numFound")-1);
1023 	solr_string_append_const(buffer, ":\"");
1024 	solr_string_appends(buffer, "numFound", sizeof("numFound")-1);
1025 	solr_string_append_const(buffer, "\";");
1026 
1027 	solr_string_append_const(buffer, "i:");
1028 	solr_string_appends(buffer, num_found, solr_strlen(num_found));
1029 	solr_string_appendc(buffer, ';');
1030 
1031 	/* Writing the start property */
1032 	solr_string_append_const(buffer, "s:");
1033 	solr_string_append_long(buffer, sizeof("start")-1);
1034 	solr_string_append_const(buffer, ":\"");
1035 	solr_string_appends(buffer, "start", sizeof("start")-1);
1036 	solr_string_append_const(buffer, "\";");
1037 
1038 	solr_string_append_const(buffer, "i:");
1039 	solr_string_appends(buffer, start, solr_strlen(start));
1040 	solr_string_appendc(buffer, ';');
1041 
1042 	/* writing max score property */
1043 	if (max_score)
1044 	{
1045 	    solr_string_append_const(buffer, "s:");
1046 	    solr_string_append_long(buffer, sizeof("maxScore")-1);
1047 	    solr_string_append_const(buffer, ":\"");
1048 	    solr_string_appends(buffer, "maxScore", sizeof("maxScore")-1);
1049 	    solr_string_append_const(buffer, "\";");
1050 
1051 	    solr_string_append_const(buffer, "d:");
1052 	    solr_string_appends(buffer, max_score, solr_strlen(max_score));
1053 	    solr_string_appendc(buffer, ';');
1054 	}
1055 
1056 	/* Writing the docs property */
1057 
1058 	solr_string_append_const(buffer, "s:");
1059 	solr_string_append_long(buffer, sizeof("docs")-1);
1060 	solr_string_append_const(buffer, ":\"");
1061 	solr_string_appends(buffer, "docs", sizeof("docs")-1);
1062 	solr_string_append_const(buffer, "\";");
1063 
1064 	if (document_count)
1065 	{
1066 		/* Grab all the first /response/result/doc node */
1067 		xmlNode *curr_doc = node->children;
1068 
1069 		long int curr_doc_index = 0L;
1070 
1071 		/* Array opener */
1072 		solr_string_append_const(buffer, "a:");
1073 		solr_string_append_long(buffer, document_count);
1074 		solr_string_append_const(buffer, ":{");
1075 
1076 		while(curr_doc != NULL)
1077 		{
1078 			/* Absolutely no assumptions. At least for now. */
1079 			if (XML_ELEMENT_NODE == curr_doc->type && solr_xml_match_node(curr_doc, "doc"))
1080 			{
1081 				/* This is where you decided whether to use SolrDocument or StdClass */
1082 				/* parse_mode value of 0 creates SolrObject; 1 creates SolrDocument */
1083 				document_encoder_functions[parse_mode](curr_doc, buffer, SOLR_ENCODE_ARRAY_INDEX, curr_doc_index, parse_mode);
1084 
1085 				curr_doc_index++;
1086 			}
1087 
1088 			curr_doc = curr_doc->next;
1089 		}
1090 
1091 		solr_write_array_closer(buffer); /* Array closer */
1092 
1093 	} else {
1094 
1095 		solr_string_append_const(buffer, "b:0;"); /* This means there are no docs */
1096 	}
1097 
1098 	solr_write_object_closer(buffer); /* Object closer */
1099 
1100 	xmlXPathFreeContext(xpathctxt);
1101 
1102 	xmlXPathFreeObject(xpathObj);
1103 }
1104 /* }}} */
1105 
1106 /* {{{ 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) */
1107 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)
1108 {
1109 	/* SolrObject should not contain nulls because of how magic functionality is implemented */
1110 	solr_write_variable_opener(node, buffer, enc_type, array_index);
1111 
1112 	/* Setting nulls to boolean false */
1113 	solr_string_append_const(buffer, "b:0;");
1114 }
1115 /* }}} */
1116 
1117 /* {{{ 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) */
1118 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)
1119 {
1120 	solr_char_t *data_value = (solr_char_t *) solr_xml_get_node_contents(node);
1121 	long int boolean_value = (!strcmp("true", data_value))? 1 : 0;
1122 
1123 	solr_write_variable_opener(node, buffer, enc_type, array_index);
1124 	solr_string_append_const(buffer, "b:");
1125 	solr_string_append_long(buffer, boolean_value);
1126 
1127 	solr_string_appendc(buffer, ';');
1128 }
1129 /* }}} */
1130 
1131 /* {{{ 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) */
1132 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)
1133 {
1134 	solr_char_t *data_value = (solr_char_t *) solr_xml_get_node_contents(node);
1135 
1136 	size_t data_value_len   = solr_strlen(data_value);
1137 
1138 	solr_write_variable_opener(node, buffer, enc_type, array_index);
1139 
1140 	solr_string_append_const(buffer, "i:");
1141 
1142 	solr_string_appends(buffer, data_value, data_value_len);
1143 
1144 	solr_string_appendc(buffer, ';');
1145 }
1146 /* }}} */
1147 
1148 /* {{{ 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) */
1149 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)
1150 {
1151 	solr_char_t *data_value = (solr_char_t *) solr_xml_get_node_contents(node);
1152 
1153 	size_t data_value_len   = solr_strlen(data_value);
1154 
1155 	solr_write_variable_opener(node, buffer, enc_type, array_index);
1156 
1157 	solr_string_append_const(buffer, "d:");
1158 
1159 	if (strcmp(data_value, "NaN" ) == 0) {
1160 	    data_value = (solr_char_t *)"NAN";
1161 	}
1162 
1163 	solr_string_appends(buffer, data_value, data_value_len);
1164 
1165 	solr_string_appendc(buffer, ';');
1166 }
1167 /* }}} */
1168 
1169 /* {{{ 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) */
1170 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)
1171 {
1172 	solr_char_t *data_value = (solr_char_t *) solr_xml_get_node_contents(node);
1173 
1174 	size_t data_value_len   = solr_strlen(data_value);
1175 
1176 	solr_write_variable_opener(node, buffer, enc_type, array_index);
1177 
1178 	solr_string_append_const(buffer, "s:");
1179 
1180 	solr_string_append_long(buffer, data_value_len);
1181 
1182 	solr_string_append_const(buffer, ":\"");
1183 
1184 	solr_string_appends(buffer, data_value, data_value_len);
1185 
1186 	solr_string_append_const(buffer, "\";");
1187 }
1188 /* }}} */
1189 
1190 /* {{{ 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) */
1191 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)
1192 {
1193 	xmlNode *curr_node = NULL;
1194 
1195 	long int current_index = 0L;
1196 
1197 	solr_write_array_opener(node, buffer, enc_type, array_index);
1198 
1199 	curr_node = node->children;
1200 
1201 	while(curr_node != NULL)
1202 	{
1203 		if (XML_ELEMENT_NODE == curr_node->type)
1204 		{
1205 			solr_encode_xml_node(curr_node, buffer, SOLR_ENCODE_ARRAY_INDEX, current_index, parse_mode);
1206 
1207 			current_index++;
1208 		}
1209 
1210 		curr_node = curr_node->next;
1211 	}
1212 
1213 	solr_write_array_closer(buffer);
1214 }
1215 /* }}} */
1216 
1217 
1218 /* {{{ 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) */
1219 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)
1220 {
1221 	xmlNode *curr_node = NULL;
1222 
1223 	solr_write_object_opener(node, buffer, enc_type, array_index);
1224 
1225 	curr_node = node->children;
1226 
1227 	while(curr_node != NULL)
1228 	{
1229 		if (XML_ELEMENT_NODE == curr_node->type)
1230 		{
1231 		    solr_encode_xml_node(curr_node, buffer, SOLR_ENCODE_OBJECT_PROPERTY, 0L, parse_mode);
1232 		}
1233 
1234 		curr_node = curr_node->next;
1235 	}
1236 
1237 	solr_write_object_closer(buffer);
1238 }
1239 /* }}} */
1240 
1241 /**
1242  * Used to digest Xml response messages from Solr
1243  *
1244  */
1245 /* {{{ PHP_SOLR_API void solr_encode_generic_xml_response(solr_string_t *buffer, const solr_char_t *serialized, int size, long int parse_mode) */
1246 PHP_SOLR_API void solr_encode_generic_xml_response(solr_string_t *buffer, const solr_char_t *serialized, int size, long int parse_mode)
1247 {
1248 	xmlDoc *doc = xmlReadMemory(serialized, size, NULL, "UTF-8", XML_PARSE_RECOVER);
1249 	xmlNode *root = NULL;
1250 
1251 	if (!doc)
1252 	{
1253 		php_error_docref(NULL, E_WARNING, "Error loading XML document");
1254 
1255 		return;
1256 	}
1257 
1258 	root = xmlDocGetRootElement(doc);
1259 
1260 	if (!root)
1261 	{
1262 		xmlFreeDoc(doc);
1263 
1264 		php_error_docref(NULL, E_WARNING, "Error loading root of XML document");
1265 
1266 		return;
1267 	}
1268 
1269 	parse_mode = ((parse_mode < 0L) ? 0L : ((parse_mode > 1L) ? 1L : parse_mode));
1270 
1271 	solr_encode_object(root, buffer, SOLR_ENCODE_STANDALONE, 0L, parse_mode);
1272 
1273 	if (buffer->len == 0)
1274 	{
1275 		php_error_docref(NULL, E_WARNING, "Error parsing XML document");
1276 	}
1277 
1278 	xmlFreeDoc(doc);
1279 }
1280 /* }}} */
1281 
1282 
1283 /* {{{ PHP_SOLR_API int solr_is_supported_response_writer(const solr_char_t * response_writer, int length) */
1284 PHP_SOLR_API int solr_is_supported_response_writer(const solr_char_t * response_writer, int length)
1285 {
1286 	if (length < 1)
1287 	{
1288 		return 0;
1289 	}
1290 
1291 	if (0 == strcmp(response_writer, SOLR_PHP_SERIALIZED_RESPONSE_WRITER))
1292 	{
1293 		return 1;
1294 	}
1295 
1296 	if (0 == strcmp(response_writer, SOLR_XML_RESPONSE_WRITER))
1297 	{
1298 		return 1;
1299 	}
1300 
1301 	if (0 == strcmp(response_writer, SOLR_JSON_RESPONSE_WRITER))
1302 	{
1303 		return 1;
1304 	}
1305 
1306 	return 0;
1307 }
1308 /* }}} */
1309 
1310 /* {{{ PHP_SOLR_API solr_char_t *solr_get_json_error_msg(solr_json_error_codes_t error_code) */
1311 PHP_SOLR_API solr_char_t *solr_get_json_error_msg(solr_json_error_codes_t error_code)
1312 {
1313 	switch(error_code)
1314 	{
1315 		case  SOLR_JSON_ERROR_DEPTH:
1316 			return "JSON maximum recursion depth was exceeded";
1317 		break;
1318 
1319 		case  SOLR_JSON_ERROR_STATE_MISMATCH:
1320 			return "JSON error state mismatch";
1321 		break;
1322 
1323 		case  SOLR_JSON_ERROR_CTRL_CHAR:
1324 			return "JSON control character was encountered";
1325 		break;
1326 
1327 		case  SOLR_JSON_ERROR_SYNTAX:
1328 			return "JSON syntax error";
1329 		break;
1330 
1331 		case  SOLR_JSON_ERROR_UTF8:
1332 			return "JSON UTF8 error";
1333 		break;
1334 
1335 		default :
1336 			return "JSON unknown error";
1337 		break;
1338 	}
1339 }
1340 /* }}} */
1341 
1342 /* {{{ PHP_SOLR_API int solr_json_to_php_native(solr_string_t *buffer, const solr_char_t *json_string, int json_string_length) */
1343 PHP_SOLR_API int solr_json_to_php_native(solr_string_t *buffer, const solr_char_t *json_string, int json_string_length)
1344 {
1345     /* todo php7 review if we ever need that indirection with ret_val */
1346     /* JSON recursion depth. default is 512 */
1347     long recursion_depth = 1024L;
1348 
1349 
1350     long json_error = 0L;
1351 
1352     php_serialize_data_t var_hash;
1353 
1354     smart_str serialize_buffer = {0};
1355 
1356     /* return value for the function */
1357     zval json_decode_ret_val, *json_decode_ret_val_ptr;
1358 
1359     zend_uchar json_decode_ret_val_type = IS_NULL;
1360 
1361     json_decode_ret_val_ptr = &json_decode_ret_val;
1362 
1363     php_json_decode(&json_decode_ret_val, (char *) json_string, json_string_length, 1, recursion_depth);
1364 
1365     json_error = solr_get_json_last_error();
1366     /* Why ? todo investigate */
1367     /* solr_string_set(buffer, "i:99;", sizeof("i:99;")); */
1368 
1369     if (json_error > 0)
1370     {
1371         zval_dtor(&json_decode_ret_val);
1372 
1373         php_error_docref(NULL, E_WARNING, "JSON error. JSON->PHP serialization error");
1374 
1375         return (int) json_error;
1376     }
1377 
1378     memset(&var_hash, 0, sizeof(php_serialize_data_t));
1379 
1380     PHP_VAR_SERIALIZE_INIT(var_hash);
1381 
1382     php_var_serialize(&serialize_buffer, &json_decode_ret_val, &var_hash);
1383 
1384     json_decode_ret_val_type = Z_TYPE_P(json_decode_ret_val_ptr);
1385 
1386     zval_dtor(&json_decode_ret_val);
1387 
1388     solr_string_set(buffer, serialize_buffer.s->val, serialize_buffer.s->len);
1389 
1390     PHP_VAR_SERIALIZE_DESTROY(var_hash);
1391 
1392     smart_str_free(&serialize_buffer);
1393     /* return value should not be of NULL type. NULL means an error has occurred */
1394     if (json_decode_ret_val_type == IS_NULL)
1395     {
1396         php_error_docref(NULL, E_WARNING, "JSON error. Error occurred in php_json_decode(). Raw JSON string is \n %s \n", (char *) json_string);
1397 /* json_error always fails to detect an error.
1398  * todo investigate
1399  */
1400         return (int) SOLR_JSON_ERROR_SERIALIZATION;
1401     }
1402 
1403     return (int) json_error;
1404 }
1405 /* }}} */
1406 
1407 PHP_SOLR_API long solr_get_json_last_error(void)
1408 {
1409     long json_error;
1410     zval json_last_error_ret_val, *object_p;
1411 
1412     zval *json_last_error_params = NULL;
1413     zval json_last_error_function_name;
1414 
1415     ZVAL_STRING(&json_last_error_function_name, "json_last_error");
1416     /* object instance to perform the method call */
1417     object_p = (zval *) NULL;
1418     call_user_function(EG(function_table), object_p, &json_last_error_function_name, &json_last_error_ret_val, 0, json_last_error_params);
1419 
1420     json_error = Z_LVAL(json_last_error_ret_val);
1421 
1422     zval_dtor(&json_last_error_ret_val);
1423 #ifdef PHP_7
1424     zval_dtor(&json_last_error_function_name);
1425 #endif
1426     return json_error;
1427 }
1428 
1429 static inline int solr_pcre_replace_into_buffer(solr_string_t *buffer, char * search, char *replace)
1430 {
1431     zend_string *result;
1432     int limit = -1;
1433 #if PHP_VERSION_ID >= 70300
1434     size_t replace_count = -1;
1435 #else
1436     int replace_count = -1;
1437 #endif
1438     zend_string *regex_str = zend_string_init(search, strlen(search), 0);
1439     zend_string *subject_str = zend_string_init(buffer->str, buffer->len, 0);
1440 #if PHP_VERSION_ID >= 70200
1441     zend_string *replace_str = zend_string_init(replace, strlen(replace), 0);
1442 #else
1443     zval replace_val;
1444     ZVAL_STRING(&replace_val, replace);
1445 #endif
1446 
1447     result = php_pcre_replace(
1448             regex_str,
1449             subject_str,
1450             buffer->str,
1451             buffer->len,
1452 #if PHP_VERSION_ID >= 70200
1453             replace_str,
1454 #else
1455             &replace_val,
1456             0,
1457 #endif
1458             limit,
1459             &replace_count
1460     );
1461 
1462     solr_string_set_ex(buffer, (solr_char_t *)result->val, (size_t)result->len);
1463 /*    fprintf(stdout, "%s", buffer->str); */
1464     efree(result);
1465 #if PHP_VERSION_ID >= 70200
1466     zend_string_release(replace_str);
1467 #else
1468     zval_ptr_dtor(&replace_val);
1469 #endif
1470     zend_string_release(regex_str);
1471     zend_string_release(subject_str);
1472 
1473     return SUCCESS;
1474 }
1475 
1476 /* serialized array to serialized object */
1477 PHP_SOLR_API int solr_sarray_to_sobject(solr_string_t *buffer)
1478 {
1479     return solr_pcre_replace_into_buffer(buffer, "/a\\:([0-9]+):{s/i", "O:10:\"SolrObject\":\\1:{s");
1480 }
1481 /* serialized object to serialized array */
1482 PHP_SOLR_API int solr_sobject_to_sarray(solr_string_t *buffer)
1483 {
1484     return solr_pcre_replace_into_buffer(buffer, "/O:10:\"SolrObject\":([0-9]+):{s/i", "a:\\1:{s");
1485 }
1486 
1487 /* }}} */
1488 
1489 /* todo document and block this */
1490 PHP_SOLR_API int solr_solrfunc_update_string(zval *obj, solr_char_t *key, int key_len, solr_char_t *value, int value_len)
1491 {
1492     solr_function_t *function;
1493     solr_string_t *string;
1494 
1495 #ifdef PHP_7
1496     string = pemalloc(sizeof(solr_string_t), SOLR_FUNCTIONS_PERSISTENT);
1497 #endif
1498     memset(string, 0, sizeof(solr_string_t));
1499     if (solr_fetch_function_entry(obj, &function) == FAILURE)
1500     {
1501         return FAILURE;
1502     }
1503 
1504     solr_string_set(string, (solr_char_t *)value, value_len);
1505     if (zend_hash_str_update_ptr(function->params, key, key_len, (void *)string) == NULL ) {
1506         solr_string_free(string);
1507         return FAILURE;
1508     }
1509 
1510     return SUCCESS;
1511 }
1512 
1513 PHP_SOLR_API int solr_solrfunc_fetch_string(zval *obj, solr_char_t *key, int key_len, solr_string_t **string)
1514 {
1515     solr_function_t *function;
1516     if (solr_fetch_function_entry(obj, &function) == FAILURE)
1517     {
1518         return FAILURE;
1519     }
1520 
1521     if ((*string = zend_hash_str_find_ptr(function->params, key, key_len)) == NULL) {
1522         return FAILURE;
1523     }
1524 
1525     return SUCCESS;
1526 }
1527 
1528 PHP_SOLR_API int solr_solrfunc_display_string(zval *obj, solr_char_t *key, int key_len, zval **return_value)
1529 {
1530     solr_string_t *field_string_ptr = NULL;
1531     memset(&field_string_ptr, 0, sizeof(solr_string_t *));
1532 
1533     if (solr_solrfunc_fetch_string(obj, key, key_len, &field_string_ptr) == SUCCESS)
1534     {
1535         ZVAL_STRINGL(*return_value, field_string_ptr->str, field_string_ptr->len);
1536         return SUCCESS;
1537     } else {
1538         php_error_docref(NULL, E_ERROR, "Unable to fetch string");
1539         return FAILURE;
1540     }
1541 }
1542 
1543 PHP_SOLR_API void solr_solrfunc_to_string(solr_function_t *function, solr_string_t **dest)
1544 {
1545     solr_string_t *buffer = *dest;
1546 
1547     solr_string_appends(buffer, (solr_char_t *)"{!", sizeof("{!")-1);
1548     solr_string_appends(buffer, function->name, function->name_length);
1549     solr_string_appendc(buffer, ' ');
1550 
1551     solr_string_t *value;
1552     zend_string *key;
1553     zend_ulong num_idx;
1554     ZEND_HASH_FOREACH_KEY_PTR(function->params, num_idx, key, value)
1555     {
1556         (void)num_idx; /* silent -Wunused-but-set-variable */
1557 
1558         /* key is only maintained internally */
1559         if (key) {
1560             solr_string_appends(buffer, key->val, key->len-1);
1561         }
1562 
1563         solr_string_appendc(buffer, '=');
1564         if (strpbrk(value->str, " ") != NULL && strpbrk(value->str,"'") == NULL) {
1565             solr_string_appendc(buffer, '\'');
1566             solr_string_append_solr_string (buffer, value);
1567             solr_string_appendc(buffer, '\'');
1568         } else {
1569             solr_string_append_solr_string (buffer, value);
1570         }
1571         solr_string_appendc(buffer, ' ');
1572     } ZEND_HASH_FOREACH_END();
1573     solr_string_remove_last_char(buffer);
1574     solr_string_appendc(buffer, '}');
1575     /* todo handle localParams argument */
1576 }
1577 
1578 PHP_SOLR_API void solr_destroy_ustream_ex(solr_ustream_t *stream)
1579 {
1580     if (stream->content_info->filename.len > 0) {
1581         solr_string_free(&stream->content_info->filename);
1582     }
1583     pefree(stream->content_info, 0);
1584     pefree(stream, 0);
1585 }
1586 
1587 PHP_SOLR_API void solr_destroy_ustream_zv(zval *obj)
1588 {
1589     solr_ustream_t *entry = Z_PTR_P(obj);
1590     solr_destroy_ustream_ex(entry);
1591 }
1592 
1593 PHP_SOLR_API int solr_fetch_ustream_entry(zval *objptr, solr_ustream_t **stream_entry)
1594 {
1595     zval rv, *index_zv;
1596     zend_ulong index = 0;
1597     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);
1598 
1599     index = Z_LVAL_P(index_zv);
1600     if ((*stream_entry = zend_hash_index_find_ptr(SOLR_GLOBAL(ustreams), index)) == NULL) {
1601         php_error_docref(NULL, E_WARNING, "Invalid Update Stream Index %ld. HashTable index does not exist.", index);
1602         php_error_docref(NULL, E_WARNING, SOLR_ERROR_1008_MSG, SOLR_FILE_LINE_FUNC);
1603         return FAILURE;
1604     }
1605     return SUCCESS;
1606 }
1607 
1608 /*
1609  * Local variables:
1610  * tab-width: 4
1611  * c-basic-offset: 4
1612  * End:
1613  * vim600: fdm=marker
1614  * vim: noet sw=4 ts=4
1615  */
1616