From 949195d28b4e4bf06a690b50379a22312f4f80a5 Mon Sep 17 00:00:00 2001 From: Rasmus Lerdorf Date: Tue, 3 Feb 2015 08:02:42 -0800 Subject: [PATCH 001/104] PHP7 Support --- php_memcached.c | 1197 +++++++++++++++++++-------------------- php_memcached.h | 2 +- php_memcached_private.h | 2 +- php_memcached_server.c | 478 ++++++++-------- php_memcached_server.h | 4 +- php_memcached_session.c | 78 +-- 6 files changed, 838 insertions(+), 923 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index c1bce93b..33570992 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -122,14 +122,6 @@ php_memc_t* i_obj = NULL; \ struct memc_obj* m_obj = NULL; -#define MEMC_METHOD_FETCH_OBJECT \ - i_obj = (php_memc_t *) zend_object_store_get_object( object TSRMLS_CC ); \ - m_obj = i_obj->obj; \ - if (!m_obj) { \ - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Memcached constructor was not called"); \ - return; \ - } - #ifndef DVAL_TO_LVAL #ifdef _WIN64 # define DVAL_TO_LVAL(d, l) \ @@ -150,12 +142,6 @@ #define RETURN_FROM_GET RETURN_FALSE -#if (PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION < 3) -#define zend_parse_parameters_none() \ - zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") -#endif - - /**************************************** Structures and definitions ****************************************/ @@ -165,8 +151,6 @@ enum memcached_compression_type { }; typedef struct { - zend_object zo; - struct memc_obj { memcached_st *memc; zend_bool compression; @@ -182,8 +166,22 @@ typedef struct { zend_bool is_pristine; int rescode; int memc_errno; + zend_object zo; } php_memc_t; +static inline php_memc_t *php_memc_fetch_object(zend_object *obj) { + return (php_memc_t *)((char *)(obj) - XtOffsetOf(php_memc_t, zo)); +} +#define Z_MEMC_OBJ_P(zv) php_memc_fetch_object(Z_OBJ_P(zv)); + +#define MEMC_METHOD_FETCH_OBJECT \ + i_obj = Z_MEMC_OBJ_P(object); \ + m_obj = i_obj->obj; \ + if (!m_obj) { \ + php_error_docref(NULL, E_WARNING, "Memcached constructor was not called"); \ + return; \ + } + #ifdef HAVE_MEMCACHED_PROTOCOL typedef struct { @@ -244,41 +242,41 @@ static PHP_INI_MH(OnUpdateCompressionType) { if (!new_value) { MEMC_G(compression_type_real) = COMPRESSION_TYPE_FASTLZ; - } else if (!strcmp(new_value, "fastlz")) { + } else if (!strcmp(new_value->val, "fastlz")) { MEMC_G(compression_type_real) = COMPRESSION_TYPE_FASTLZ; - } else if (!strcmp(new_value, "zlib")) { + } else if (!strcmp(new_value->val, "zlib")) { MEMC_G(compression_type_real) = COMPRESSION_TYPE_ZLIB; } else { return FAILURE; } - return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC); + return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); } static PHP_INI_MH(OnUpdateSerializer) { if (!new_value) { MEMC_G(serializer) = SERIALIZER_DEFAULT; - } else if (!strcmp(new_value, "php")) { + } else if (!strcmp(new_value->val, "php")) { MEMC_G(serializer) = SERIALIZER_PHP; #ifdef HAVE_MEMCACHED_IGBINARY - } else if (!strcmp(new_value, "igbinary")) { + } else if (!strcmp(new_value->val, "igbinary")) { MEMC_G(serializer) = SERIALIZER_IGBINARY; #endif // IGBINARY #ifdef HAVE_JSON_API - } else if (!strcmp(new_value, "json")) { + } else if (!strcmp(new_value->val, "json")) { MEMC_G(serializer) = SERIALIZER_JSON; - } else if (!strcmp(new_value, "json_array")) { + } else if (!strcmp(new_value->val, "json_array")) { MEMC_G(serializer) = SERIALIZER_JSON_ARRAY; #endif // JSON #ifdef HAVE_MEMCACHED_MSGPACK - } else if (!strcmp(new_value, "msgpack")) { + } else if (!strcmp(new_value->val, "msgpack")) { MEMC_G(serializer) = SERIALIZER_MSGPACK; #endif // msgpack } else { return FAILURE; } - return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC); + return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); } /* {{{ INI entries */ @@ -316,9 +314,9 @@ PHP_INI_END() /**************************************** Forward declarations ****************************************/ -static int php_memc_handle_error(php_memc_t *i_obj, memcached_return status TSRMLS_DC); -static char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t *flags, enum memcached_serializer serializer, enum memcached_compression_type compression_type TSRMLS_DC); -static int php_memc_zval_from_payload(zval *value, const char *payload, size_t payload_len, uint32_t flags, enum memcached_serializer serializer TSRMLS_DC); +static int php_memc_handle_error(php_memc_t *i_obj, memcached_return status); +static char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t *flags, enum memcached_serializer serializer, enum memcached_compression_type compression_type); +static int php_memc_zval_from_payload(zval *value, const char *payload, size_t payload_len, uint32_t flags, enum memcached_serializer serializer); static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key); static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key); static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool by_key); @@ -326,68 +324,66 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke static void php_memc_delete_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key); static void php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key); static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key); -static memcached_return php_memc_do_cache_callback(zval *memc_obj, zend_fcall_info *fci, zend_fcall_info_cache *fcc, char *key, size_t key_len, zval *value TSRMLS_DC); -static int php_memc_do_result_callback(zval *memc_obj, zend_fcall_info *fci, zend_fcall_info_cache *fcc, memcached_result_st *result TSRMLS_DC); +static memcached_return php_memc_do_cache_callback(zval *memc_obj, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string *key, zval *value); +static int php_memc_do_result_callback(zval *memc_obj, zend_fcall_info *fci, zend_fcall_info_cache *fcc, memcached_result_st *result); static memcached_return php_memc_do_serverlist_callback(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context); static memcached_return php_memc_do_stats_callback(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context); static memcached_return php_memc_do_version_callback(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context); -static void php_memc_destroy(struct memc_obj *m_obj, zend_bool persistent TSRMLS_DC); +static void php_memc_destroy(struct memc_obj *m_obj, zend_bool persistent); /**************************************** Method implementations ****************************************/ -char *php_memc_printable_func (zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TSRMLS_DC) +char *php_memc_printable_func (zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) { char *buffer = NULL; - if (fci->object_ptr) { - spprintf (&buffer, 0, "%s::%s", Z_OBJCE_P (fci->object_ptr)->name, fci_cache->function_handler->common.function_name); + if (fci->object) { + spprintf (&buffer, 0, "%s::%s", fci->object->ce->name->val, fci_cache->function_handler->common.function_name); } else { - if (Z_TYPE_P (fci->function_name) == IS_OBJECT) { - spprintf (&buffer, 0, "%s", Z_OBJCE_P (fci->function_name)->name); + if (Z_TYPE (fci->function_name) == IS_OBJECT) { + spprintf (&buffer, 0, "%s", Z_OBJCE (fci->function_name)->name->val); } else { - spprintf (&buffer, 0, "%s", Z_STRVAL_P (fci->function_name)); + spprintf (&buffer, 0, "%s", Z_STRVAL (fci->function_name)); } } return buffer; } -static zend_bool php_memcached_on_new_callback(zval *object, zend_fcall_info *fci, zend_fcall_info_cache *fci_cache, char *persistent_id, int persistent_id_len TSRMLS_DC) +static zend_bool php_memcached_on_new_callback(zval *object, zend_fcall_info *fci, zend_fcall_info_cache *fci_cache, zend_string *persistent_id) { - zend_bool retval = 1; - zval pid_z; - zval *retval_ptr, *pid_z_ptr = &pid_z; - zval **params[2]; + zend_bool ret = 1; + zval retval; + zval params[2]; - INIT_ZVAL(pid_z); if (persistent_id) { - ZVAL_STRINGL(pid_z_ptr, persistent_id, persistent_id_len, 1); + ZVAL_STR(¶ms[1], persistent_id); + } else { + ZVAL_NULL(¶ms[1]); } /* Call the cb */ - params[0] = &object; - params[1] = &pid_z_ptr; + ZVAL_COPY_VALUE(¶ms[0], object); fci->params = params; fci->param_count = 2; - fci->retval_ptr_ptr = &retval_ptr; + fci->retval = &retval; fci->no_separation = 1; - if (zend_call_function(fci, fci_cache TSRMLS_CC) == FAILURE) { - char *buf = php_memc_printable_func (fci, fci_cache TSRMLS_CC); - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to invoke 'on_new' callback %s()", buf); + if (zend_call_function(fci, fci_cache) == FAILURE) { + char *buf = php_memc_printable_func (fci, fci_cache); + php_error_docref(NULL, E_WARNING, "Failed to invoke 'on_new' callback %s()", buf); efree (buf); - retval = 0; + ret = 0; } - zval_dtor(pid_z_ptr); - if (retval_ptr) { - zval_ptr_dtor(&retval_ptr); - } - return retval; + zval_ptr_dtor(¶ms[0]); + zval_ptr_dtor(¶ms[1]); + zval_ptr_dtor(&retval); + return ret; } static int le_memc, le_memc_sess; @@ -404,32 +400,28 @@ static PHP_METHOD(Memcached, __construct) zval *object = getThis(); php_memc_t *i_obj; struct memc_obj *m_obj = NULL; - char *persistent_id = NULL, *conn_str = NULL; - int persistent_id_len, conn_str_len; + zend_string *persistent_id = NULL; + zend_string *conn_str = NULL; zend_bool is_persistent = 0; - - char *plist_key = NULL; - int plist_key_len = 0; - + zend_string *plist_key = NULL; zend_fcall_info fci = {0}; zend_fcall_info_cache fci_cache; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!f!s", &persistent_id, &persistent_id_len, &fci, &fci_cache, &conn_str, &conn_str_len) == FAILURE) { - ZVAL_NULL(object); + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!f!S", &persistent_id, &fci, &fci_cache, &conn_str) == FAILURE) { + ZEND_CTOR_MAKE_NULL(); return; } - i_obj = (php_memc_t *) zend_object_store_get_object(object TSRMLS_CC); + i_obj = Z_MEMC_OBJ_P(object); i_obj->is_pristine = 0; - if (persistent_id && *persistent_id) { - zend_rsrc_list_entry *le = NULL; + if (persistent_id && persistent_id->len) { + zend_resource *le; is_persistent = 1; - plist_key_len = spprintf(&plist_key, 0, "memcached:id=%s", persistent_id); - plist_key_len += 1; - - if (zend_hash_find(&EG(persistent_list), plist_key, plist_key_len, (void *)&le) == SUCCESS) { + plist_key = zend_string_alloc(sizeof("memcached:id=") + persistent_id->len - 1, 0); + snprintf(plist_key->val, plist_key->len+1, "memcached:id=%s", persistent_id->val); + if ((le = zend_hash_find_ptr(&EG(persistent_list), plist_key)) != NULL) { if (le->type == php_memc_list_entry()) { m_obj = (struct memc_obj *) le->ptr; } @@ -443,27 +435,27 @@ static PHP_METHOD(Memcached, __construct) m_obj = pecalloc(1, sizeof(*m_obj), is_persistent); if (m_obj == NULL) { if (plist_key) { - efree(plist_key); + zend_string_release(plist_key); } - php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory: cannot allocate handle"); + php_error_docref(NULL, E_ERROR, "out of memory: cannot allocate handle"); /* not reached */ } if (conn_str) { - m_obj->memc = php_memc_create_str(conn_str, conn_str_len); + m_obj->memc = php_memc_create_str(conn_str->val, conn_str->len); if (!m_obj->memc) { char error_buffer[1024]; if (plist_key) { - efree(plist_key); + zend_string_release(plist_key); } #ifdef HAVE_LIBMEMCACHED_CHECK_CONFIGURATION - if (libmemcached_check_configuration(conn_str, conn_str_len, error_buffer, sizeof(error_buffer)) != MEMCACHED_SUCCESS) { - php_error_docref(NULL TSRMLS_CC, E_ERROR, "configuration error %s", error_buffer); + if (libmemcached_check_configuration(conn_str->val, conn_str->len, error_buffer, sizeof(error_buffer)) != MEMCACHED_SUCCESS) { + php_error_docref(NULL, E_ERROR, "configuration error %s", error_buffer); } else { - php_error_docref(NULL TSRMLS_CC, E_ERROR, "could not allocate libmemcached structure"); + php_error_docref(NULL, E_ERROR, "could not allocate libmemcached structure"); } #else - php_error_docref(NULL TSRMLS_CC, E_ERROR, "could not allocate libmemcached structure"); + php_error_docref(NULL, E_ERROR, "could not allocate libmemcached structure"); #endif /* not reached */ } @@ -471,9 +463,9 @@ static PHP_METHOD(Memcached, __construct) m_obj->memc = memcached_create(NULL); if (m_obj->memc == NULL) { if (plist_key) { - efree(plist_key); + zend_string_release(plist_key); } - php_error_docref(NULL TSRMLS_CC, E_ERROR, "could not allocate libmemcached structure"); + php_error_docref(NULL, E_ERROR, "could not allocate libmemcached structure"); /* not reached */ } } @@ -487,15 +479,15 @@ static PHP_METHOD(Memcached, __construct) i_obj->is_pristine = 1; if (fci.size) { /* will be 0 when not available */ - if (!php_memcached_on_new_callback(object, &fci, &fci_cache, persistent_id, persistent_id_len TSRMLS_CC) || EG(exception)) { + if (!php_memcached_on_new_callback(object, &fci, &fci_cache, persistent_id) || EG(exception)) { /* error calling or exception thrown from callback */ if (plist_key) { - efree(plist_key); + zend_string_release(plist_key); } i_obj->obj = NULL; if (is_persistent) { - php_memc_destroy(m_obj, is_persistent TSRMLS_CC); + php_memc_destroy(m_obj, is_persistent); } return; @@ -503,23 +495,23 @@ static PHP_METHOD(Memcached, __construct) } if (is_persistent) { - zend_rsrc_list_entry le; + zend_resource le; le.type = php_memc_list_entry(); le.ptr = m_obj; - if (zend_hash_update(&EG(persistent_list), (char *)plist_key, - plist_key_len, (void *)&le, sizeof(le), NULL) == FAILURE) { + GC_REFCOUNT(&le) = 1; + if (zend_hash_update_mem(&EG(persistent_list), plist_key, &le, sizeof(le)) == NULL) { if (plist_key) { - efree(plist_key); + zend_string_release(plist_key); } - php_error_docref(NULL TSRMLS_CC, E_ERROR, "could not register persistent entry"); + php_error_docref(NULL, E_ERROR, "could not register persistent entry"); /* not reached */ } } } if (plist_key) { - efree(plist_key); + zend_string_release(plist_key); } } /* }}} */ @@ -543,10 +535,8 @@ PHP_METHOD(Memcached, getByKey) /* {{{ -- php_memc_get_impl */ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { - char *key = NULL; - int key_len = 0; - char *server_key = NULL; - int server_key_len = 0; + zend_string *key; + zend_string *server_key; const char *payload = NULL; size_t payload_len = 0; uint32_t flags = 0; @@ -562,12 +552,12 @@ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) MEMC_METHOD_INIT_VARS; if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|f!zz", &server_key, - &server_key_len, &key, &key_len, &fci, &fcc, &cas_token, &udf_flags) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|f!zz", &server_key, &key, + &fci, &fcc, &cas_token, &udf_flags) == FAILURE) { return; } } else { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|f!zz", &key, &key_len, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|f!zz", &key, &fci, &fcc, &cas_token, &udf_flags) == FAILURE) { return; } @@ -576,13 +566,13 @@ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) MEMC_METHOD_FETCH_OBJECT; i_obj->rescode = MEMCACHED_SUCCESS; - if (key_len == 0 || strchr(key, ' ')) { + if (key->len == 0 || strchr(key->val, ' ')) { i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; RETURN_FROM_GET; } - keys[0] = key; - key_lens[0] = key_len; + keys[0] = key->val; + key_lens[0] = key->len; uint64_t orig_cas_flag; orig_cas_flag = memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS); @@ -590,17 +580,17 @@ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) /* * Enable CAS support, but only if it is currently disabled. */ - if (cas_token && PZVAL_IS_REF(cas_token) && orig_cas_flag == 0) { + if (cas_token && Z_IS_REF(cas_token) && orig_cas_flag == 0) { memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1); } - status = memcached_mget_by_key(m_obj->memc, server_key, server_key_len, keys, key_lens, 1); + status = memcached_mget_by_key(m_obj->memc, server_key->val, server_key->len, keys, key_lens, 1); - if (cas_token && PZVAL_IS_REF(cas_token) && orig_cas_flag == 0) { + if (cas_token && Z_IS_REF(cas_token) && orig_cas_flag == 0) { memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, orig_cas_flag); } - if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) { + if (php_memc_handle_error(i_obj, status) < 0) { RETURN_FROM_GET; } @@ -622,10 +612,10 @@ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) } if (status == MEMCACHED_NOTFOUND && fci.size != 0) { - status = php_memc_do_cache_callback(getThis(), &fci, &fcc, key, key_len, return_value TSRMLS_CC); + status = php_memc_do_cache_callback(getThis(), &fci, &fcc, key, return_value); } - if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) { + if (php_memc_handle_error(i_obj, status) < 0) { memcached_result_free(&result); RETURN_FROM_GET; } @@ -651,18 +641,22 @@ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) cas = memcached_result_cas(&result); } - if (php_memc_zval_from_payload(return_value, payload, payload_len, flags, m_obj->serializer TSRMLS_CC) < 0) { + if (php_memc_zval_from_payload(return_value, payload, payload_len, flags, m_obj->serializer) < 0) { memcached_result_free(&result); i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE; RETURN_FROM_GET; } if (cas_token) { + ZVAL_DEREF(cas_token); + SEPARATE_ZVAL(cas_token); zval_dtor(cas_token); ZVAL_DOUBLE(cas_token, (double)cas); } if (udf_flags) { + ZVAL_DEREF(udf_flags); + SEPARATE_ZVAL(udf_flags); zval_dtor(udf_flags); ZVAL_LONG(udf_flags, MEMC_VAL_GET_USER_FLAGS(flags)); } @@ -691,10 +685,9 @@ PHP_METHOD(Memcached, getMultiByKey) static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { zval *keys = NULL; - char *server_key = NULL; - int server_key_len = 0; + zend_string *server_key; size_t num_keys = 0; - zval **entry = NULL; + zval *entry = NULL; const char *payload = NULL; size_t payload_len = 0; const char **mkeys = NULL; @@ -706,7 +699,7 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke zval *cas_tokens = NULL; zval *udf_flags = NULL; uint64_t orig_cas_flag = 0; - zval *value; + zval value; long get_flags = 0; int i = 0; zend_bool preserve_order; @@ -715,12 +708,12 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke MEMC_METHOD_INIT_VARS; if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|zlz", &server_key, - &server_key_len, &keys, &cas_tokens, &get_flags, &udf_flags) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa/|zlz", &server_key, + &keys, &cas_tokens, &get_flags, &udf_flags) == FAILURE) { return; } } else { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/|zlz", &keys, &cas_tokens, &get_flags, &udf_flags) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|zlz", &keys, &cas_tokens, &get_flags, &udf_flags) == FAILURE) { return; } } @@ -738,24 +731,21 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke * Create the array of keys for libmemcached. If none of the keys were valid * (strings), set bad key result code and return. */ - for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(keys)); - zend_hash_get_current_data(Z_ARRVAL_P(keys), (void**)&entry) == SUCCESS; - zend_hash_move_forward(Z_ARRVAL_P(keys))) { - - if (Z_TYPE_PP(entry) != IS_STRING) { + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(keys), entry) { + if (Z_TYPE_P(entry) != IS_STRING) { convert_to_string_ex(entry); } - if (Z_TYPE_PP(entry) == IS_STRING && Z_STRLEN_PP(entry) > 0) { - mkeys[i] = Z_STRVAL_PP(entry); - mkeys_len[i] = Z_STRLEN_PP(entry); + if (Z_TYPE_P(entry) == IS_STRING && Z_STRLEN_P(entry) > 0) { + mkeys[i] = Z_STRVAL_P(entry); + mkeys_len[i] = Z_STRLEN_P(entry); if (preserve_order) { - add_assoc_null_ex(return_value, mkeys[i], mkeys_len[i] + 1); + add_assoc_null_ex(return_value, mkeys[i], mkeys_len[i]); } i++; } - } + } ZEND_HASH_FOREACH_END(); if (i == 0) { i_obj->rescode = MEMCACHED_NOTFOUND; @@ -767,21 +757,21 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke /* * Enable CAS support, but only if it is currently disabled. */ - if (cas_tokens && PZVAL_IS_REF(cas_tokens)) { + if (cas_tokens && Z_IS_REF(cas_tokens)) { orig_cas_flag = memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS); if (orig_cas_flag == 0) { memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1); } } - status = memcached_mget_by_key(m_obj->memc, server_key, server_key_len, mkeys, mkeys_len, i); + status = memcached_mget_by_key(m_obj->memc, server_key->val, server_key->len, mkeys, mkeys_len, i); /* Handle error, but ignore, there might still be some result */ - php_memc_handle_error(i_obj, status TSRMLS_CC); + php_memc_handle_error(i_obj, status); /* * Restore the CAS support flag, but only if we had to turn it on. */ - if (cas_tokens && PZVAL_IS_REF(cas_tokens) && orig_cas_flag == 0) { + if (cas_tokens && Z_IS_REF(cas_tokens) && orig_cas_flag == 0) { memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, orig_cas_flag); } @@ -793,15 +783,16 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke * returned as doubles, because we cannot store potential 64-bit values in longs. */ if (cas_tokens) { - if (PZVAL_IS_REF(cas_tokens)) { + if (Z_IS_REF(cas_tokens)) { /* cas_tokens was passed by reference, we'll create an array for it. */ + ZVAL_DEREF(cas_tokens); + SEPARATE_ZVAL(cas_tokens); zval_dtor(cas_tokens); array_init(cas_tokens); } else { /* Not passed by reference, we allow this (eg.: if you specify null to not enable cas but you want to use the udf_flags parameter). We destruct it and set it to null for the peace of mind. */ - zval_dtor(cas_tokens); cas_tokens = NULL; } } @@ -811,6 +802,8 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke * returned as longs. */ if (udf_flags) { + ZVAL_DEREF(udf_flags); + SEPARATE_ZVAL(udf_flags); zval_dtor(udf_flags); array_init(udf_flags); } @@ -821,7 +814,7 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke if (status != MEMCACHED_SUCCESS) { status = MEMCACHED_SOME_ERRORS; - php_memc_handle_error(i_obj, status TSRMLS_CC); + php_memc_handle_error(i_obj, status); continue; } @@ -838,13 +831,11 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke memcpy (res_key, tmp_key, res_key_len >= MEMCACHED_MAX_KEY ? MEMCACHED_MAX_KEY - 1 : res_key_len); res_key [res_key_len] = '\0'; - ALLOC_INIT_ZVAL(value); - - if (php_memc_zval_from_payload(value, payload, payload_len, flags, m_obj->serializer TSRMLS_CC) < 0) { + if (php_memc_zval_from_payload(&value, payload, payload_len, flags, m_obj->serializer) < 0) { zval_ptr_dtor(&value); if (EG(exception)) { status = MEMC_RES_PAYLOAD_FAILURE; - php_memc_handle_error(i_obj, status TSRMLS_CC); + php_memc_handle_error(i_obj, status); memcached_quit(m_obj->memc); break; @@ -855,7 +846,7 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke continue; } - add_assoc_zval_ex(return_value, res_key, res_key_len+1, value); + add_assoc_zval_ex(return_value, res_key, res_key_len+1, &value); if (cas_tokens) { cas = memcached_result_cas(&result); add_assoc_double_ex(cas_tokens, res_key, res_key_len+1, (double)cas); @@ -870,10 +861,14 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke if (EG(exception)) { /* XXX: cas_tokens should only be set on success, currently we're destructive */ if (cas_tokens) { + ZVAL_DEREF(cas_tokens); + SEPARATE_ZVAL(cas_tokens); zval_dtor(cas_tokens); ZVAL_NULL(cas_tokens); } if (udf_flags) { + ZVAL_DEREF(udf_flags); + SEPARATE_ZVAL(udf_flags); zval_dtor(udf_flags); ZVAL_NULL(udf_flags); } @@ -903,11 +898,10 @@ PHP_METHOD(Memcached, getDelayedByKey) static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { zval *keys = NULL; - char *server_key = NULL; - int server_key_len = 0; + zend_string *server_key; zend_bool with_cas = 0; size_t num_keys = 0; - zval **entry = NULL; + zval *entry = NULL; const char **mkeys = NULL; size_t *mkeys_len = NULL; uint64_t orig_cas_flag = 0; @@ -918,12 +912,12 @@ static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ MEMC_METHOD_INIT_VARS; if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|bf!", &server_key, - &server_key_len, &keys, &with_cas, &fci, &fcc) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa/|bf!", &server_key, + &keys, &with_cas, &fci, &fcc) == FAILURE) { return; } } else { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/|bf!", &keys, &with_cas, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|bf!", &keys, &with_cas, &fci, &fcc) == FAILURE) { return; } @@ -940,20 +934,17 @@ static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ mkeys = safe_emalloc(num_keys, sizeof(*mkeys), 0); mkeys_len = safe_emalloc(num_keys, sizeof(*mkeys_len), 0); - for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(keys)); - zend_hash_get_current_data(Z_ARRVAL_P(keys), (void**)&entry) == SUCCESS; - zend_hash_move_forward(Z_ARRVAL_P(keys))) { - - if (Z_TYPE_PP(entry) != IS_STRING) { + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(keys), entry) { + if (Z_TYPE_P(entry) != IS_STRING) { convert_to_string_ex(entry); } if (Z_TYPE_PP(entry) == IS_STRING && Z_STRLEN_PP(entry) > 0) { - mkeys[i] = Z_STRVAL_PP(entry); - mkeys_len[i] = Z_STRLEN_PP(entry); + mkeys[i] = Z_STRVAL_P(entry); + mkeys_len[i] = Z_STRLEN_P(entry); i++; } - } + } ZEND_HASH_FOREACH_END(); if (i == 0) { i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; @@ -976,7 +967,7 @@ static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ /* * Issue the request, but collect results only if the result callback is provided. */ - status = memcached_mget_by_key(m_obj->memc, server_key, server_key_len, mkeys, mkeys_len, i); + status = memcached_mget_by_key(m_obj->memc, server_key->val, server_key->len, mkeys, mkeys_len, i); /* * Restore the CAS support flag, but only if we had to turn it on. @@ -987,7 +978,7 @@ static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ efree(mkeys); efree(mkeys_len); - if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) { + if (php_memc_handle_error(i_obj, status) < 0) { zval_dtor(return_value); RETURN_FALSE; } @@ -1001,7 +992,7 @@ static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ memcached_result_create(m_obj->memc, &result); while ((memcached_fetch_result(m_obj->memc, &result, &status)) != NULL) { - if (php_memc_do_result_callback(getThis(), &fci, &fcc, &result TSRMLS_CC) < 0) { + if (php_memc_do_result_callback(getThis(), &fci, &fcc, &result) < 0) { status = MEMCACHED_FAILURE; break; } @@ -1012,7 +1003,7 @@ static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ if (status == MEMCACHED_END) { status = MEMCACHED_SUCCESS; } - if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) { + if (php_memc_handle_error(i_obj, status) < 0) { RETURN_FALSE; } } @@ -1029,7 +1020,7 @@ PHP_METHOD(Memcached, fetch) size_t res_key_len = 0; const char *payload = NULL; size_t payload_len = 0; - zval *value; + zval value; uint32_t flags = 0; uint64_t cas = 0; memcached_result_st result; @@ -1045,7 +1036,7 @@ PHP_METHOD(Memcached, fetch) memcached_result_create(m_obj->memc, &result); if ((memcached_fetch_result(m_obj->memc, &result, &status)) == NULL) { - php_memc_handle_error(i_obj, status TSRMLS_CC); + php_memc_handle_error(i_obj, status); memcached_result_free(&result); RETURN_FALSE; } @@ -1057,9 +1048,7 @@ PHP_METHOD(Memcached, fetch) res_key_len = memcached_result_key_length(&result); cas = memcached_result_cas(&result); - ALLOC_INIT_ZVAL(value); - - if (php_memc_zval_from_payload(value, payload, payload_len, flags, m_obj->serializer TSRMLS_CC) < 0) { + if (php_memc_zval_from_payload(&value, payload, payload_len, flags, m_obj->serializer) < 0) { memcached_result_free(&result); zval_ptr_dtor(&value); i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE; @@ -1067,14 +1056,14 @@ PHP_METHOD(Memcached, fetch) } array_init(return_value); - add_assoc_stringl_ex(return_value, ZEND_STRS("key"), res_key, res_key_len, 1); - add_assoc_zval_ex(return_value, ZEND_STRS("value"), value); + add_assoc_stringl_ex(return_value, ZEND_STRL("key"), (char *)res_key, res_key_len); + add_assoc_zval_ex(return_value, ZEND_STRL("value"), &value); if (cas != 0) { /* XXX: also check against ULLONG_MAX or memc_behavior */ - add_assoc_double_ex(return_value, ZEND_STRS("cas"), (double)cas); + add_assoc_double_ex(return_value, ZEND_STRL("cas"), (double)cas); } if (MEMC_VAL_GET_USER_FLAGS(flags) != 0) { - add_assoc_long_ex(return_value, ZEND_STRS("flags"), MEMC_VAL_GET_USER_FLAGS(flags)); + add_assoc_long_ex(return_value, ZEND_STRL("flags"), MEMC_VAL_GET_USER_FLAGS(flags)); } memcached_result_free(&result); @@ -1089,7 +1078,7 @@ PHP_METHOD(Memcached, fetchAll) size_t res_key_len = 0; const char *payload = NULL; size_t payload_len = 0; - zval *value, *entry; + zval value, entry; uint32_t flags; uint64_t cas = 0; memcached_result_st result; @@ -1114,9 +1103,7 @@ PHP_METHOD(Memcached, fetchAll) res_key_len = memcached_result_key_length(&result); cas = memcached_result_cas(&result); - ALLOC_INIT_ZVAL(value); - - if (php_memc_zval_from_payload(value, payload, payload_len, flags, m_obj->serializer TSRMLS_CC) < 0) { + if (php_memc_zval_from_payload(&value, payload, payload_len, flags, m_obj->serializer) < 0) { memcached_result_free(&result); zval_ptr_dtor(&value); zval_dtor(return_value); @@ -1124,23 +1111,22 @@ PHP_METHOD(Memcached, fetchAll) RETURN_FALSE; } - MAKE_STD_ZVAL(entry); - array_init(entry); - add_assoc_stringl_ex(entry, ZEND_STRS("key"), res_key, res_key_len, 1); - add_assoc_zval_ex(entry, ZEND_STRS("value"), value); + array_init(&entry); + add_assoc_stringl_ex(&entry, ZEND_STRL("key"), (char *)res_key, res_key_len); + add_assoc_zval_ex(&entry, ZEND_STRL("value"), &value); if (cas != 0) { /* XXX: also check against ULLONG_MAX or memc_behavior */ - add_assoc_double_ex(entry, ZEND_STRS("cas"), (double)cas); + add_assoc_double_ex(&entry, ZEND_STRL("cas"), (double)cas); } if (MEMC_VAL_GET_USER_FLAGS(flags) != 0) { - add_assoc_long_ex(entry, ZEND_STRS("flags"), MEMC_VAL_GET_USER_FLAGS(flags)); + add_assoc_long_ex(&entry, ZEND_STRL("flags"), MEMC_VAL_GET_USER_FLAGS(flags)); } - add_next_index_zval(return_value, entry); + add_next_index_zval(return_value, &entry); } memcached_result_free(&result); - if (status != MEMCACHED_END && php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) { + if (status != MEMCACHED_END && php_memc_handle_error(i_obj, status) < 0) { zval_dtor(return_value); RETURN_FALSE; } @@ -1227,13 +1213,11 @@ PHP_METHOD(Memcached, setMultiByKey) static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { zval *entries; - char *server_key = NULL; - int server_key_len = 0; + zend_string *server_key; time_t expiration = 0; long udf_flags = 0; - zval **entry; - char *str_key; - uint str_key_len; + zval *entry; + zend_string *str_key = NULL; ulong num_key; char *payload; size_t payload_len; @@ -1241,15 +1225,16 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke uint32_t retry = 0; memcached_return status; char tmp_key[MEMCACHED_MAX_KEY]; + int tmp_len = 0; MEMC_METHOD_INIT_VARS; if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa|ll", &server_key, - &server_key_len, &entries, &expiration, &udf_flags) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa|ll", &server_key, + &entries, &expiration, &udf_flags) == FAILURE) { return; } } else { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|ll", &entries, &expiration, &udf_flags) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|ll", &entries, &expiration, &udf_flags) == FAILURE) { return; } } @@ -1263,24 +1248,21 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke */ if (udf_flags > 0) { if ((uint32_t) udf_flags > MEMC_VAL_USER_FLAGS_MAX) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "udf_flags will be limited to %u", MEMC_VAL_USER_FLAGS_MAX); + php_error_docref(NULL, E_WARNING, "udf_flags will be limited to %u", MEMC_VAL_USER_FLAGS_MAX); } } - for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(entries)); - zend_hash_get_current_data(Z_ARRVAL_P(entries), (void**)&entry) == SUCCESS; - zend_hash_move_forward(Z_ARRVAL_P(entries))) { - int key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(entries), &str_key, &str_key_len, &num_key, 0, NULL); - - if (key_type == HASH_KEY_IS_LONG) { + ZEND_HASH_FOREACH_KEY_VAL (Z_ARRVAL_P(entries), num_key, str_key, entry) { + if (str_key) { + str_key = zend_string_init(str_key->val, str_key->len, 0); + } else if (num_key || num_key == 0) { /* Array keys are unsigned, but php integers are signed. * Keys must be converted to signed strings that match * php integers. */ assert(sizeof(tmp_key) >= sizeof(ZEND_TOSTR(LONG_MIN))); - - str_key_len = sprintf(tmp_key, "%ld", (long)num_key) + 1; - str_key = (char *)tmp_key; - } else if (key_type != HASH_KEY_IS_STRING) { + tmp_len = sprintf(tmp_key, "%ld", (long)num_key); + str_key = zend_string_init(tmp_key, tmp_len, 0); + } else { continue; } @@ -1293,26 +1275,31 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) udf_flags)); } - payload = php_memc_zval_to_payload(*entry, &payload_len, &flags, m_obj->serializer, m_obj->compression_type TSRMLS_CC); + payload = php_memc_zval_to_payload(entry, &payload_len, &flags, m_obj->serializer, m_obj->compression_type); if (payload == NULL) { i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE; + zend_string_release(str_key); RETURN_FALSE; } retry: if (!by_key) { - status = memcached_set(m_obj->memc, str_key, str_key_len-1, payload, payload_len, expiration, flags); + status = memcached_set(m_obj->memc, str_key->val, str_key->len, payload, payload_len, expiration, flags); + zend_string_release(str_key); } else { - status = memcached_set_by_key(m_obj->memc, server_key, server_key_len, str_key, str_key_len-1, payload, payload_len, expiration, flags); + status = memcached_set_by_key(m_obj->memc, server_key->val, server_key->len, str_key->val, str_key->len, payload, payload_len, expiration, flags); + zend_string_release(str_key); } - if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) { + if (php_memc_handle_error(i_obj, status) < 0) { PHP_MEMC_FAILOVER_RETRY + zend_string_release(str_key); efree(payload); RETURN_FALSE; } + zend_string_release(str_key); efree(payload); - } + } ZEND_HASH_FOREACH_END(); RETURN_TRUE; } @@ -1382,16 +1369,12 @@ PHP_METHOD(Memcached, replaceByKey) } /* }}} */ - /* {{{ -- php_memc_store_impl */ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool by_key) { - char *key = NULL; - int key_len = 0; - char *server_key = NULL; - int server_key_len = 0; - char *s_value = NULL; - int s_value_len = 0; + zend_string *key; + zend_string *server_key; + zend_string *s_value; zval s_zvalue; zval *value; long expiration = 0; @@ -1405,41 +1388,33 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool if (by_key) { if (op == MEMC_OP_APPEND || op == MEMC_OP_PREPEND) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss", &server_key, - &server_key_len, &key, &key_len, &s_value, &s_value_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSS", &server_key, &key, &s_value) == FAILURE) { return; } - INIT_ZVAL(s_zvalue); value = &s_zvalue; - ZVAL_STRINGL(value, s_value, s_value_len, 0); + ZVAL_STR(value, s_value); } else if (op == MEMC_OP_TOUCH) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &server_key, - &server_key_len, &key, &key_len, &expiration) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|l", &server_key, &key, &expiration) == FAILURE) { return; } } else { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssz|ll", &server_key, - &server_key_len, &key, &key_len, &value, &expiration, &udf_flags) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSz|ll", &server_key, &key, &value, &expiration, &udf_flags) == FAILURE) { return; } } } else { if (op == MEMC_OP_APPEND || op == MEMC_OP_PREPEND) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &key, &key_len, - &s_value, &s_value_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &key, &s_value) == FAILURE) { return; } - INIT_ZVAL(s_zvalue); value = &s_zvalue; - ZVAL_STRINGL(value, s_value, s_value_len, 0); + ZVAL_STR(value, s_value); } else if (op == MEMC_OP_TOUCH) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &key, - &key_len, &expiration) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|l", &key, &expiration) == FAILURE) { return; } } else { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|ll", &key, &key_len, - &value, &expiration, &udf_flags) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|ll", &key, &value, &expiration, &udf_flags) == FAILURE) { return; } } @@ -1448,7 +1423,7 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool MEMC_METHOD_FETCH_OBJECT; i_obj->rescode = MEMCACHED_SUCCESS; - if (key_len == 0 || strchr(key, ' ')) { + if (key->len == 0 || strchr(key->val, ' ')) { i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; RETURN_FALSE; } @@ -1460,7 +1435,7 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool * append/prepend new data, and store it again. */ if (op == MEMC_OP_APPEND || op == MEMC_OP_PREPEND) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot append/prepend with compression turned on"); + php_error_docref(NULL, E_WARNING, "cannot append/prepend with compression turned on"); return; } MEMC_VAL_SET_FLAG(flags, MEMC_VAL_COMPRESSED); @@ -1472,7 +1447,7 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool */ if (udf_flags > 0) { if ((uint32_t) udf_flags > MEMC_VAL_USER_FLAGS_MAX) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "udf_flags will be limited to %u", MEMC_VAL_USER_FLAGS_MAX); + php_error_docref(NULL, E_WARNING, "udf_flags will be limited to %u", MEMC_VAL_USER_FLAGS_MAX); } MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) udf_flags)); } @@ -1480,11 +1455,11 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool if (op == MEMC_OP_TOUCH) { #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x01000016 if (memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "using touch command with binary protocol is not recommended with libmemcached versions below 1.0.16"); + php_error_docref(NULL, E_WARNING, "using touch command with binary protocol is not recommended with libmemcached versions below 1.0.16"); } #endif } else { - payload = php_memc_zval_to_payload(value, &payload_len, &flags, m_obj->serializer, m_obj->compression_type TSRMLS_CC); + payload = php_memc_zval_to_payload(value, &payload_len, &flags, m_obj->serializer, m_obj->compression_type); if (payload == NULL) { i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE; RETURN_FALSE; @@ -1493,56 +1468,56 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool retry: switch (op) { case MEMC_OP_SET: - if (!server_key) { - status = memcached_set(m_obj->memc, key, key_len, payload, payload_len, expiration, flags); + if (!server_key->val) { + status = memcached_set(m_obj->memc, key->val, key->len, payload, payload_len, expiration, flags); } else { - status = memcached_set_by_key(m_obj->memc, server_key, server_key_len, key, - key_len, payload, payload_len, expiration, flags); + status = memcached_set_by_key(m_obj->memc, server_key->val, server_key->len, key->val, + key->len, payload, payload_len, expiration, flags); } break; #ifdef HAVE_MEMCACHED_TOUCH case MEMC_OP_TOUCH: - if (!server_key) { - status = memcached_touch(m_obj->memc, key, key_len, expiration); + if (!server_key->val) { + status = memcached_touch(m_obj->memc, key->val, key->len, expiration); } else { - status = memcached_touch_by_key(m_obj->memc, server_key, server_key_len, key, - key_len, expiration); + status = memcached_touch_by_key(m_obj->memc, server_key->val, server_key->len, key->val, + key->len, expiration); } break; #endif case MEMC_OP_ADD: - if (!server_key) { - status = memcached_add(m_obj->memc, key, key_len, payload, payload_len, expiration, flags); + if (!server_key->val) { + status = memcached_add(m_obj->memc, key->val, key->len, payload, payload_len, expiration, flags); } else { - status = memcached_add_by_key(m_obj->memc, server_key, server_key_len, key, - key_len, payload, payload_len, expiration, flags); + status = memcached_add_by_key(m_obj->memc, server_key->val, server_key->len, key->val, + key->len, payload, payload_len, expiration, flags); } break; case MEMC_OP_REPLACE: - if (!server_key) { - status = memcached_replace(m_obj->memc, key, key_len, payload, payload_len, expiration, flags); + if (!server_key->val) { + status = memcached_replace(m_obj->memc, key->val, key->len, payload, payload_len, expiration, flags); } else { - status = memcached_replace_by_key(m_obj->memc, server_key, server_key_len, key, - key_len, payload, payload_len, expiration, flags); + status = memcached_replace_by_key(m_obj->memc, server_key->val, server_key->len, key->val, + key->len, payload, payload_len, expiration, flags); } break; case MEMC_OP_APPEND: - if (!server_key) { - status = memcached_append(m_obj->memc, key, key_len, payload, payload_len, expiration, flags); + if (!server_key->val) { + status = memcached_append(m_obj->memc, key->val, key->len, payload, payload_len, expiration, flags); } else { - status = memcached_append_by_key(m_obj->memc, server_key, server_key_len, key, - key_len, payload, payload_len, expiration, flags); + status = memcached_append_by_key(m_obj->memc, server_key->val, server_key->len, key->val, + key->len, payload, payload_len, expiration, flags); } break; case MEMC_OP_PREPEND: - if (!server_key) { - status = memcached_prepend(m_obj->memc, key, key_len, payload, payload_len, expiration, flags); + if (!server_key->val) { + status = memcached_prepend(m_obj->memc, key->val, key->len, payload, payload_len, expiration, flags); } else { - status = memcached_prepend_by_key(m_obj->memc, server_key, server_key_len, key, - key_len, payload, payload_len, expiration, flags); + status = memcached_prepend_by_key(m_obj->memc, server_key->val, server_key->len, key->val, + key->len, payload, payload_len, expiration, flags); } break; @@ -1553,7 +1528,7 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool break; } - if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) { + if (php_memc_handle_error(i_obj, status) < 0) { PHP_MEMC_FAILOVER_RETRY RETVAL_FALSE; } else { @@ -1571,10 +1546,8 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { double cas_d; uint64_t cas; - char *key = NULL; - int key_len = 0; - char *server_key = NULL; - int server_key_len = 0; + zend_string *key; + zend_string *server_key; zval *value; time_t expiration = 0; long udf_flags = 0; @@ -1585,13 +1558,13 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) MEMC_METHOD_INIT_VARS; if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dssz|ll", &cas_d, &server_key, - &server_key_len, &key, &key_len, &value, &expiration, &udf_flags) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "dSSz|ll", &cas_d, &server_key, &key, + &value, &expiration, &udf_flags) == FAILURE) { return; } } else { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dsz|ll", &cas_d, &key, &key_len, - &value, &expiration, &udf_flags) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "dSz|ll", &cas_d, &key, &value, + &expiration, &udf_flags) == FAILURE) { return; } } @@ -1599,7 +1572,7 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) MEMC_METHOD_FETCH_OBJECT; i_obj->rescode = MEMCACHED_SUCCESS; - if (key_len == 0 || strchr(key, ' ')) { + if (key->len == 0 || strchr(key->val, ' ')) { i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; RETURN_FALSE; } @@ -1616,24 +1589,24 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) */ if (udf_flags > 0) { if ((uint32_t) udf_flags > MEMC_VAL_USER_FLAGS_MAX) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "udf_flags will be limited to %u", MEMC_VAL_USER_FLAGS_MAX); + php_error_docref(NULL, E_WARNING, "udf_flags will be limited to %u", MEMC_VAL_USER_FLAGS_MAX); } MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) udf_flags)); } - payload = php_memc_zval_to_payload(value, &payload_len, &flags, m_obj->serializer, m_obj->compression_type TSRMLS_CC); + payload = php_memc_zval_to_payload(value, &payload_len, &flags, m_obj->serializer, m_obj->compression_type); if (payload == NULL) { i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE; RETURN_FALSE; } if (by_key) { - status = memcached_cas_by_key(m_obj->memc, server_key, server_key_len, key, key_len, payload, payload_len, expiration, flags, cas); + status = memcached_cas_by_key(m_obj->memc, server_key->val, server_key->len, key->val, key->len, payload, payload_len, expiration, flags, cas); } else { - status = memcached_cas(m_obj->memc, key, key_len, payload, payload_len, expiration, flags, cas); + status = memcached_cas(m_obj->memc, key->val, key->len, payload, payload_len, expiration, flags, cas); } efree(payload); - if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) { + if (php_memc_handle_error(i_obj, status) < 0) { RETURN_FALSE; } @@ -1692,40 +1665,34 @@ PHP_METHOD(Memcached, deleteMultiByKey) /* {{{ -- php_memc_delete_impl */ static void php_memc_delete_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { - char *key = NULL; - int key_len = 0; - char *server_key = NULL; - int server_key_len = 0; + zend_string *key, *server_key; time_t expiration = 0; memcached_return status; MEMC_METHOD_INIT_VARS; if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &server_key, - &server_key_len, &key, &key_len, &expiration) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|l", &server_key, &key, &expiration) == FAILURE) { return; } } else { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &key, &key_len, - &expiration) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|l", &key, &expiration) == FAILURE) { return; } - server_key = key; - server_key_len = key_len; + server_key = zend_string_copy(key); } MEMC_METHOD_FETCH_OBJECT; i_obj->rescode = MEMCACHED_SUCCESS; - if (key_len == 0 || strchr(key, ' ')) { + if (key->len == 0 || strchr(key->val, ' ')) { i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; RETURN_FALSE; } - status = memcached_delete_by_key(m_obj->memc, server_key, server_key_len, key, - key_len, expiration); + status = memcached_delete_by_key(m_obj->memc, server_key->val, server_key->len, key->val, + key->len, expiration); - if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) { + if (php_memc_handle_error(i_obj, status) < 0) { RETURN_FALSE; } @@ -1737,21 +1704,19 @@ static void php_memc_delete_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) static void php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { zval *entries; - char *server_key = NULL; - int server_key_len = 0; + zend_string *server_key; time_t expiration = 0; - zval **entry; + zval *entry; memcached_return status; MEMC_METHOD_INIT_VARS; if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|l", &server_key, - &server_key_len, &entries, &expiration) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa/|l", &server_key, &entries, &expiration) == FAILURE) { return; } } else { - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/|l", &entries, &expiration) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|l", &entries, &expiration) == FAILURE) { return; } } @@ -1760,31 +1725,28 @@ static void php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by i_obj->rescode = MEMCACHED_SUCCESS; array_init(return_value); - for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(entries)); - zend_hash_get_current_data(Z_ARRVAL_P(entries), (void**)&entry) == SUCCESS; - zend_hash_move_forward(Z_ARRVAL_P(entries))) { - - if (Z_TYPE_PP(entry) != IS_STRING) { + ZEND_HASH_FOREACH_VAL (Z_ARRVAL_P(entries), entry) { + if (Z_TYPE_P(entry) != IS_STRING) { convert_to_string_ex(entry); } - if (Z_STRLEN_PP(entry) == 0) { + if (Z_STRLEN_P(entry) == 0) { continue; } - if (!by_key) { - server_key = Z_STRVAL_PP(entry); - server_key_len = Z_STRLEN_PP(entry); + if (by_key) { + status = memcached_delete_by_key(m_obj->memc, server_key->val, server_key->len, Z_STRVAL_P(entry), Z_STRLEN_P(entry), expiration); + } else { + status = memcached_delete_by_key(m_obj->memc, Z_STRVAL_P(entry), Z_STRLEN_P(entry), Z_STRVAL_P(entry), Z_STRLEN_P(entry), expiration); } - status = memcached_delete_by_key(m_obj->memc, server_key, server_key_len, Z_STRVAL_PP(entry), Z_STRLEN_PP(entry), expiration); - if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) { - add_assoc_long(return_value, Z_STRVAL_PP(entry), status); + if (php_memc_handle_error(i_obj, status) < 0) { + add_assoc_long(return_value, Z_STRVAL_P(entry), status); } else { - add_assoc_bool(return_value, Z_STRVAL_PP(entry), 1); + add_assoc_bool(return_value, Z_STRVAL_P(entry), 1); } - } + } ZEND_HASH_FOREACH_END(); return; } @@ -1793,8 +1755,7 @@ static void php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by /* {{{ -- php_memc_incdec_impl */ static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key, zend_bool incr) { - char *key, *server_key; - int key_len, server_key_len; + zend_string *key, *server_key; long offset = 1; uint64_t value, initial = 0; time_t expiry = 0; @@ -1805,11 +1766,11 @@ static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key, MEMC_METHOD_INIT_VARS; if (!by_key) { - if (zend_parse_parameters(n_args TSRMLS_CC, "s|lll", &key, &key_len, &offset, &initial, &expiry) == FAILURE) { + if (zend_parse_parameters(n_args, "S|lll", &key, &offset, &initial, &expiry) == FAILURE) { return; } } else { - if (zend_parse_parameters(n_args TSRMLS_CC, "ss|lll", &server_key, &server_key_len, &key, &key_len, &offset, &initial, &expiry) == FAILURE) { + if (zend_parse_parameters(n_args, "SS|lll", &server_key, &key, &offset, &initial, &expiry) == FAILURE) { return; } } @@ -1817,13 +1778,13 @@ static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key, MEMC_METHOD_FETCH_OBJECT; i_obj->rescode = MEMCACHED_SUCCESS; - if (key_len == 0 || strchr(key, ' ')) { + if (key->len == 0 || strchr(key->val, ' ')) { i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; RETURN_FALSE; } if (offset < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "offset has to be > 0"); + php_error_docref(NULL, E_WARNING, "offset has to be > 0"); RETURN_FALSE; } @@ -1831,38 +1792,38 @@ static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key, if ((!by_key && n_args < 3) || (by_key && n_args < 4)) { if (by_key) { if (incr) { - status = memcached_increment_by_key(m_obj->memc, server_key, server_key_len, key, key_len, (unsigned int)offset, &value); + status = memcached_increment_by_key(m_obj->memc, server_key->val, server_key->len, key->val, key->len, (unsigned int)offset, &value); } else { - status = memcached_decrement_by_key(m_obj->memc, server_key, server_key_len, key, key_len, (unsigned int)offset, &value); + status = memcached_decrement_by_key(m_obj->memc, server_key->val, server_key->len, key->val, key->len, (unsigned int)offset, &value); } } else { if (incr) { - status = memcached_increment(m_obj->memc, key, key_len, (unsigned int)offset, &value); + status = memcached_increment(m_obj->memc, key->val, key->len, (unsigned int)offset, &value); } else { - status = memcached_decrement(m_obj->memc, key, key_len, (unsigned int)offset, &value); + status = memcached_decrement(m_obj->memc, key->val, key->len, (unsigned int)offset, &value); } } } else { if (!memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Initial value is only supported with binary protocol"); + php_error_docref(NULL, E_WARNING, "Initial value is only supported with binary protocol"); RETURN_FALSE; } if (by_key) { if (incr) { - status = memcached_increment_with_initial_by_key(m_obj->memc, server_key, server_key_len, key, key_len, (unsigned int)offset, initial, expiry, &value); + status = memcached_increment_with_initial_by_key(m_obj->memc, server_key->val, server_key->len, key->val, key->len, (unsigned int)offset, initial, expiry, &value); } else { - status = memcached_decrement_with_initial_by_key(m_obj->memc, server_key, server_key_len, key, key_len, (unsigned int)offset, initial, expiry, &value); + status = memcached_decrement_with_initial_by_key(m_obj->memc, server_key->val, server_key->len, key->val, key->len, (unsigned int)offset, initial, expiry, &value); } } else { if (incr) { - status = memcached_increment_with_initial(m_obj->memc, key, key_len, (unsigned int)offset, initial, expiry, &value); + status = memcached_increment_with_initial(m_obj->memc, key->val, key->len, (unsigned int)offset, initial, expiry, &value); } else { - status = memcached_decrement_with_initial(m_obj->memc, key, key_len, (unsigned int)offset, initial, expiry, &value); + status = memcached_decrement_with_initial(m_obj->memc, key->val, key->len, (unsigned int)offset, initial, expiry, &value); } } } - if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) { + if (php_memc_handle_error(i_obj, status) < 0) { PHP_MEMC_FAILOVER_RETRY RETURN_FALSE; } @@ -1907,14 +1868,12 @@ PHP_METHOD(Memcached, incrementByKey) Adds the given memcache server to the list */ PHP_METHOD(Memcached, addServer) { - char *host; - int host_len; + zend_string *host; long port, weight = 0; memcached_return status; MEMC_METHOD_INIT_VARS; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|l", &host, &host_len, - &port, &weight) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sl|l", &host, &port, &weight) == FAILURE) { return; } @@ -1922,18 +1881,18 @@ PHP_METHOD(Memcached, addServer) i_obj->rescode = MEMCACHED_SUCCESS; #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x01000002 - if (host[0] == '/') { /* unix domain socket */ - status = memcached_server_add_unix_socket_with_weight(m_obj->memc, host, weight); + if (host->val[0] == '/') { /* unix domain socket */ + status = memcached_server_add_unix_socket_with_weight(m_obj->memc, host->val, weight); } else if (memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_USE_UDP)) { - status = memcached_server_add_udp_with_weight(m_obj->memc, host, port, weight); + status = memcached_server_add_udp_with_weight(m_obj->memc, host->val, port, weight); } else { - status = memcached_server_add_with_weight(m_obj->memc, host, port, weight); + status = memcached_server_add_with_weight(m_obj->memc, host->val, port, weight); } #else - status = memcached_server_add_with_weight(m_obj->memc, host, port, weight); + status = memcached_server_add_with_weight(m_obj->memc, host->val, port, weight); #endif - if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) { + if (php_memc_handle_error(i_obj, status) < 0) { RETURN_FALSE; } @@ -1946,45 +1905,46 @@ PHP_METHOD(Memcached, addServer) PHP_METHOD(Memcached, addServers) { zval *servers; - zval **entry; - zval **z_host, **z_port, **z_weight = NULL; + zval *entry; + zval *z_host, *z_port, *z_weight = NULL; uint32_t weight = 0; + HashPosition pos; int entry_size, i = 0; memcached_server_st *list = NULL; memcached_return status; MEMC_METHOD_INIT_VARS; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &servers) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/", &servers) == FAILURE) { return; } MEMC_METHOD_FETCH_OBJECT; i_obj->rescode = MEMCACHED_SUCCESS; - for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(servers)), i = 0; - zend_hash_get_current_data(Z_ARRVAL_P(servers), (void **)&entry) == SUCCESS; - zend_hash_move_forward(Z_ARRVAL_P(servers)), i++) { - - if (Z_TYPE_PP(entry) != IS_ARRAY) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "server list entry #%d is not an array", i+1); + ZEND_HASH_FOREACH_VAL (Z_ARRVAL_P(servers), entry) { + if (Z_TYPE_P(entry) != IS_ARRAY) { + php_error_docref(NULL, E_WARNING, "server list entry #%d is not an array", i+1); + i++; continue; } - entry_size = zend_hash_num_elements(Z_ARRVAL_PP(entry)); + entry_size = zend_hash_num_elements(Z_ARRVAL_P(entry)); if (entry_size > 1) { - zend_hash_internal_pointer_reset(Z_ARRVAL_PP(entry)); + zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(entry), &pos); /* Check that we have a host */ - if (zend_hash_get_current_data(Z_ARRVAL_PP(entry), (void **)&z_host) == FAILURE) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not get server host for entry #%d", i+1); + if ((z_host = zend_hash_get_current_data_ex(Z_ARRVAL_P(entry), &pos)) == NULL) { + php_error_docref(NULL, E_WARNING, "could not get server host for entry #%d", i+1); + i++; continue; } /* Check that we have a port */ - if (zend_hash_move_forward(Z_ARRVAL_PP(entry)) == FAILURE || - zend_hash_get_current_data(Z_ARRVAL_PP(entry), (void **)&z_port) == FAILURE) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not get server port for entry #%d", i+1); + if (zend_hash_move_forward_ex(Z_ARRVAL_P(entry), &pos) == FAILURE || + (z_port = zend_hash_get_current_data_ex(Z_ARRVAL_P(entry), &pos)) == NULL) { + php_error_docref(NULL, E_WARNING, "could not get server port for entry #%d", i+1); + i++; continue; } @@ -1994,30 +1954,31 @@ PHP_METHOD(Memcached, addServers) weight = 0; if (entry_size > 2) { /* Try to get weight */ - if (zend_hash_move_forward(Z_ARRVAL_PP(entry)) == FAILURE || - zend_hash_get_current_data(Z_ARRVAL_PP(entry), (void **)&z_weight) == FAILURE) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not get server weight for entry #%d", i+1); + if (zend_hash_move_forward_ex(Z_ARRVAL_P(entry), &pos) == FAILURE || + (z_weight = zend_hash_get_current_data_ex(Z_ARRVAL_P(entry), &pos)) == NULL) { + php_error_docref(NULL, E_WARNING, "could not get server weight for entry #%d", i+1); } convert_to_long_ex(z_weight); - weight = Z_LVAL_PP(z_weight); + weight = Z_LVAL_P(z_weight); } - list = memcached_server_list_append_with_weight(list, Z_STRVAL_PP(z_host), - Z_LVAL_PP(z_port), weight, &status); + list = memcached_server_list_append_with_weight(list, Z_STRVAL_P(z_host), + Z_LVAL_P(z_port), weight, &status); - if (php_memc_handle_error(i_obj, status TSRMLS_CC) == 0) { + if (php_memc_handle_error(i_obj, status) == 0) { + i++; continue; } } - + i++; /* catch-all for all errors */ - php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not add entry #%d to the server list", i+1); - } + php_error_docref(NULL, E_WARNING, "could not add entry #%d to the server list", i+1); + } ZEND_HASH_FOREACH_END(); status = memcached_server_push(m_obj->memc, list); memcached_server_list_free(list); - if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) { + if (php_memc_handle_error(i_obj, status) < 0) { RETURN_FALSE; } @@ -2025,7 +1986,6 @@ PHP_METHOD(Memcached, addServers) } /* }}} */ - /* {{{ Memcached::getServerList() Returns the list of the memcache servers in use */ PHP_METHOD(Memcached, getServerList) @@ -2051,32 +2011,31 @@ PHP_METHOD(Memcached, getServerList) Returns the server identified by the given server key */ PHP_METHOD(Memcached, getServerByKey) { - char *server_key; - int server_key_len; + zend_string *server_key; php_memcached_instance_st server_instance; memcached_return error; MEMC_METHOD_INIT_VARS; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &server_key, &server_key_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &server_key) == FAILURE) { return; } MEMC_METHOD_FETCH_OBJECT; i_obj->rescode = MEMCACHED_SUCCESS; - if (server_key_len == 0 || strchr(server_key, ' ')) { + if (server_key->len == 0 || strchr(server_key->val, ' ')) { i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; RETURN_FALSE; } - server_instance = memcached_server_by_key(m_obj->memc, server_key, server_key_len, &error); + server_instance = memcached_server_by_key(m_obj->memc, server_key->val, server_key->len, &error); if (server_instance == NULL) { - php_memc_handle_error(i_obj, error TSRMLS_CC); + php_memc_handle_error(i_obj, error); RETURN_FALSE; } array_init(return_value); - add_assoc_string(return_value, "host", (char*) memcached_server_name(server_instance), 1); + add_assoc_string(return_value, "host", (char*) memcached_server_name(server_instance)); add_assoc_long(return_value, "port", memcached_server_port(server_instance)); add_assoc_long(return_value, "weight", 0); } @@ -2144,7 +2103,7 @@ PHP_METHOD(Memcached, getLastErrorMessage) MEMC_METHOD_FETCH_OBJECT; - RETURN_STRING(memcached_last_error_message(m_obj->memc), 1); + RETURN_STRING(memcached_last_error_message(m_obj->memc)); } /* }}} */ @@ -2201,7 +2160,7 @@ PHP_METHOD(Memcached, getLastDisconnectedServer) } array_init(return_value); - add_assoc_string(return_value, "host", (char*) memcached_server_name(server_instance), 1); + add_assoc_string(return_value, "host", (char*) memcached_server_name(server_instance)); add_assoc_long(return_value, "port", memcached_server_port(server_instance)); } /* }}} */ @@ -2228,7 +2187,7 @@ PHP_METHOD(Memcached, getStats) } stats = memcached_stat(m_obj->memc, NULL, &status); - php_memc_handle_error(i_obj, status TSRMLS_CC); + php_memc_handle_error(i_obj, status); if (stats == NULL) { RETURN_FALSE; } else if (status != MEMCACHED_SUCCESS && status != MEMCACHED_SOME_ERRORS) { @@ -2266,7 +2225,7 @@ PHP_METHOD(Memcached, getVersion) array_init(return_value); status = memcached_version(m_obj->memc); - if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) { + if (php_memc_handle_error(i_obj, status) < 0) { zval_dtor(return_value); RETURN_FALSE; } @@ -2284,7 +2243,7 @@ static memcached_return php_memc_dump_func_callback(const memcached_st *ptr __at const char *key, size_t key_length, void *context) { zval *ctx = (zval*) context; - add_next_index_string(ctx, (char*) key, 1); + add_next_index_string(ctx, (char*) key); return MEMCACHED_SUCCESS; } @@ -2300,7 +2259,7 @@ PHP_METHOD(Memcached, getAllKeys) array_init(return_value); rc = memcached_dump(m_obj->memc, callback, return_value, 1); - if (php_memc_handle_error(i_obj, rc TSRMLS_CC) < 0) { + if (php_memc_handle_error(i_obj, rc) < 0) { zval_dtor(return_value); RETURN_FALSE; } @@ -2315,7 +2274,7 @@ static PHP_METHOD(Memcached, flush) memcached_return status; MEMC_METHOD_INIT_VARS; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &delay) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &delay) == FAILURE) { return; } @@ -2323,7 +2282,7 @@ static PHP_METHOD(Memcached, flush) i_obj->rescode = MEMCACHED_SUCCESS; status = memcached_flush(m_obj->memc, delay); - if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) { + if (php_memc_handle_error(i_obj, status) < 0) { RETURN_FALSE; } @@ -2340,7 +2299,7 @@ static PHP_METHOD(Memcached, getOption) memcached_behavior flag; MEMC_METHOD_INIT_VARS; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &option) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &option) == FAILURE) { return; } @@ -2361,9 +2320,9 @@ static PHP_METHOD(Memcached, getOption) result = memcached_callback_get(m_obj->memc, MEMCACHED_CALLBACK_PREFIX_KEY, &retval); if (retval == MEMCACHED_SUCCESS && result) { #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX == 0x00049000 - RETURN_STRINGL(result, strlen(result) - 1, 1); + RETURN_STRINGL(result, strlen(result) - 1); #else - RETURN_STRING(result, 1); + RETURN_STRING(result); #endif } else { RETURN_EMPTY_STRING(); @@ -2381,7 +2340,7 @@ static PHP_METHOD(Memcached, getOption) case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE: case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE: if (memcached_server_count(m_obj->memc) == 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "no servers defined"); + php_error_docref(NULL, E_WARNING, "no servers defined"); return; } @@ -2396,7 +2355,7 @@ static PHP_METHOD(Memcached, getOption) } /* }}} */ -static int php_memc_set_option(php_memc_t *i_obj, long option, zval *value TSRMLS_DC) +static int php_memc_set_option(php_memc_t *i_obj, long option, zval *value) { memcached_return rc = MEMCACHED_FAILURE; memcached_behavior flag; @@ -2443,7 +2402,7 @@ static int php_memc_set_option(php_memc_t *i_obj, long option, zval *value TSRML } if (memcached_callback_set(m_obj->memc, MEMCACHED_CALLBACK_PREFIX_KEY, key) == MEMCACHED_BAD_KEY_PROVIDED) { i_obj->rescode = MEMCACHED_INVALID_ARGUMENTS; - php_error_docref(NULL TSRMLS_CC, E_WARNING, "bad key provided"); + php_error_docref(NULL, E_WARNING, "bad key provided"); return 0; } } @@ -2455,8 +2414,8 @@ static int php_memc_set_option(php_memc_t *i_obj, long option, zval *value TSRML convert_to_long(value); rc = memcached_behavior_set(m_obj->memc, flag, (uint64_t) Z_LVAL_P(value)); - if (php_memc_handle_error(i_obj, rc TSRMLS_CC) < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "error setting memcached option: %s", memcached_strerror (m_obj->memc, rc)); + if (php_memc_handle_error(i_obj, rc) < 0) { + php_error_docref(NULL, E_WARNING, "error setting memcached option: %s", memcached_strerror (m_obj->memc, rc)); return 0; } @@ -2505,7 +2464,7 @@ static int php_memc_set_option(php_memc_t *i_obj, long option, zval *value TSRML } else { m_obj->serializer = SERIALIZER_PHP; i_obj->rescode = MEMCACHED_INVALID_ARGUMENTS; - php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid serializer provided"); + php_error_docref(NULL, E_WARNING, "invalid serializer provided"); return 0; } break; @@ -2535,8 +2494,8 @@ static int php_memc_set_option(php_memc_t *i_obj, long option, zval *value TSRML } } - if (php_memc_handle_error(i_obj, rc TSRMLS_CC) < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "error setting memcached option: %s", memcached_strerror (m_obj->memc, rc)); + if (php_memc_handle_error(i_obj, rc) < 0) { + php_error_docref(NULL, E_WARNING, "error setting memcached option: %s", memcached_strerror (m_obj->memc, rc)); return 0; } break; @@ -2545,9 +2504,9 @@ static int php_memc_set_option(php_memc_t *i_obj, long option, zval *value TSRML } static -uint32_t *s_zval_to_uint32_array (zval *input, size_t *num_elements TSRMLS_DC) +uint32_t *s_zval_to_uint32_array (zval *input, size_t *num_elements) { - zval **ppzval; + zval *pzval; uint32_t *retval; size_t i = 0; @@ -2559,20 +2518,17 @@ uint32_t *s_zval_to_uint32_array (zval *input, size_t *num_elements TSRMLS_DC) retval = ecalloc(*num_elements, sizeof(uint32_t)); - for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(input)); - zend_hash_get_current_data(Z_ARRVAL_P(input), (void **) &ppzval) == SUCCESS; - zend_hash_move_forward(Z_ARRVAL_P(input)), i++) { - + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(input), pzval) { long value = 0; - if (Z_TYPE_PP(ppzval) == IS_LONG) { - value = Z_LVAL_PP(ppzval); + if (Z_TYPE_P(pzval) == IS_LONG) { + value = Z_LVAL_P(pzval); } else { - zval tmp_zval, *tmp_pzval; - tmp_zval = **ppzval; - zval_copy_ctor(&tmp_zval); - tmp_pzval = &tmp_zval; + zval *tmp_zval, *tmp_pzval; + tmp_zval = pzval; + zval_copy_ctor(tmp_zval); + tmp_pzval = tmp_zval; convert_to_long(tmp_pzval); value = (Z_LVAL_P(tmp_pzval) > 0) ? Z_LVAL_P(tmp_pzval) : 0; @@ -2580,13 +2536,14 @@ uint32_t *s_zval_to_uint32_array (zval *input, size_t *num_elements TSRMLS_DC) } if (value < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "the map must contain positive integers"); + php_error_docref(NULL, E_WARNING, "the map must contain positive integers"); efree (retval); *num_elements = 0; return NULL; } retval [i] = (uint32_t) value; - } + i++; + } ZEND_HASH_FOREACH_END(); return retval; } @@ -2605,35 +2562,35 @@ PHP_METHOD(Memcached, setBucket) memcached_return rc; MEMC_METHOD_INIT_VARS; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "aa!l", &zserver_map, &zforward_map, &replicas) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "aa!l", &zserver_map, &zforward_map, &replicas) == FAILURE) { return; } MEMC_METHOD_FETCH_OBJECT; if (zend_hash_num_elements (Z_ARRVAL_P(zserver_map)) == 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "server map cannot be empty"); + php_error_docref(NULL, E_WARNING, "server map cannot be empty"); RETURN_FALSE; } if (zforward_map && zend_hash_num_elements (Z_ARRVAL_P(zserver_map)) != zend_hash_num_elements (Z_ARRVAL_P(zforward_map))) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "forward_map length must match the server_map length"); + php_error_docref(NULL, E_WARNING, "forward_map length must match the server_map length"); RETURN_FALSE; } if (replicas < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "replicas must be larger than zero"); + php_error_docref(NULL, E_WARNING, "replicas must be larger than zero"); RETURN_FALSE; } - server_map = s_zval_to_uint32_array (zserver_map, &server_map_len TSRMLS_CC); + server_map = s_zval_to_uint32_array (zserver_map, &server_map_len); if (!server_map) { RETURN_FALSE; } if (zforward_map) { - forward_map = s_zval_to_uint32_array (zforward_map, &forward_map_len TSRMLS_CC); + forward_map = s_zval_to_uint32_array (zforward_map, &forward_map_len); if (!forward_map) { efree (server_map); @@ -2643,7 +2600,7 @@ PHP_METHOD(Memcached, setBucket) rc = memcached_bucket_set (m_obj->memc, server_map, forward_map, (uint32_t) server_map_len, replicas); - if (php_memc_handle_error(i_obj, rc TSRMLS_CC) < 0) { + if (php_memc_handle_error(i_obj, rc) < 0) { retval = 0;; } @@ -2662,38 +2619,33 @@ static PHP_METHOD(Memcached, setOptions) { zval *options; zend_bool ok = 1; - uint key_len; - char *key; + zend_string *key; ulong key_index; - zval **value; + zval *value; MEMC_METHOD_INIT_VARS; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &options) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &options) == FAILURE) { return; } MEMC_METHOD_FETCH_OBJECT; - for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(options)); - zend_hash_get_current_data(Z_ARRVAL_P(options), (void *) &value) == SUCCESS; - zend_hash_move_forward(Z_ARRVAL_P(options))) { - - if (zend_hash_get_current_key_ex(Z_ARRVAL_P(options), &key, &key_len, &key_index, 0, NULL) == HASH_KEY_IS_LONG) { - zval copy = **value; - zval_copy_ctor(©); - INIT_PZVAL(©); + ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(options), key_index, key, value) { + if (key) { + php_error_docref(NULL, E_WARNING, "invalid configuration option"); + ok = 0; + } else { + zval copy; + ZVAL_DUP(©, value); - if (!php_memc_set_option(i_obj, (long) key_index, © TSRMLS_CC)) { + if (!php_memc_set_option(i_obj, (long) key_index, ©)) { ok = 0; } zval_dtor(©); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid configuration option"); - ok = 0; } - } + } ZEND_HASH_FOREACH_END(); RETURN_BOOL(ok); } @@ -2707,13 +2659,13 @@ static PHP_METHOD(Memcached, setOption) zval *value; MEMC_METHOD_INIT_VARS; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz/", &option, &value) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz/", &option, &value) == FAILURE) { return; } MEMC_METHOD_FETCH_OBJECT; - RETURN_BOOL(php_memc_set_option(i_obj, option, value TSRMLS_CC)); + RETURN_BOOL(php_memc_set_option(i_obj, option, value)); } /* }}} */ @@ -2724,29 +2676,27 @@ static PHP_METHOD(Memcached, setSaslAuthData) { MEMC_METHOD_INIT_VARS; memcached_return status; + zend_string *user, *pass; - char *user, *pass; - int user_len, pass_len; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &user, &user_len, &pass, &pass_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &user, &pass) == FAILURE) { return; } if (!MEMC_G(use_sasl)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "SASL support (memcached.use_sasl) isn't enabled in php.ini"); + php_error_docref(NULL, E_WARNING, "SASL support (memcached.use_sasl) isn't enabled in php.ini"); RETURN_FALSE; } MEMC_METHOD_FETCH_OBJECT; if (!memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "SASL is only supported with binary protocol"); + php_error_docref(NULL, E_WARNING, "SASL is only supported with binary protocol"); RETURN_FALSE; } m_obj->has_sasl_data = 1; - status = memcached_set_sasl_auth_data(m_obj->memc, user, pass); + status = memcached_set_sasl_auth_data(m_obj->memc, user->val, pass->val); - if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) { + if (php_memc_handle_error(i_obj, status) < 0) { RETURN_FALSE; } RETURN_TRUE; @@ -2784,7 +2734,7 @@ static PHP_METHOD(Memcached, getResultMessage) switch (i_obj->rescode) { case MEMC_RES_PAYLOAD_FAILURE: - RETURN_STRING("PAYLOAD FAILURE", 1); + RETURN_STRING("PAYLOAD FAILURE"); break; case MEMCACHED_ERRNO: @@ -2795,11 +2745,11 @@ static PHP_METHOD(Memcached, getResultMessage) int str_len; str_len = spprintf(&str, 0, "%s: %s", memcached_strerror(m_obj->memc, (memcached_return)i_obj->rescode), strerror(i_obj->memc_errno)); - RETURN_STRINGL(str, str_len, 0); + RETURN_STRINGL(str, str_len); } /* Fall through */ default: - RETURN_STRING(memcached_strerror(m_obj->memc, (memcached_return)i_obj->rescode), 1); + RETURN_STRING(memcached_strerror(m_obj->memc, (memcached_return)i_obj->rescode)); break; } @@ -2843,7 +2793,7 @@ static PHP_METHOD(Memcached, isPristine) ****************************************/ /* {{{ constructor/destructor */ -static void php_memc_destroy(struct memc_obj *m_obj, zend_bool persistent TSRMLS_DC) +static void php_memc_destroy(struct memc_obj *m_obj, zend_bool persistent) { #if HAVE_MEMCACHED_SASL if (m_obj->has_sasl_data) { @@ -2857,56 +2807,47 @@ static void php_memc_destroy(struct memc_obj *m_obj, zend_bool persistent TSRMLS pefree(m_obj, persistent); } -static void php_memc_free_storage(php_memc_t *i_obj TSRMLS_DC) +static void php_memc_free_storage(zend_object *obj) { - zend_object_std_dtor(&i_obj->zo TSRMLS_CC); - + php_memc_t *i_obj = php_memc_fetch_object(obj); + if (i_obj->obj && !i_obj->is_persistent) { - php_memc_destroy(i_obj->obj, 0 TSRMLS_CC); + php_memc_destroy(i_obj->obj, 0); } + zend_object_std_dtor(&i_obj->zo); i_obj->obj = NULL; efree(i_obj); } -zend_object_value php_memc_new(zend_class_entry *ce TSRMLS_DC) +zend_object *php_memc_new(zend_class_entry *ce) { - zend_object_value retval; - php_memc_t *i_obj; - - i_obj = ecalloc(1, sizeof(*i_obj)); - zend_object_std_init( &i_obj->zo, ce TSRMLS_CC ); -#if PHP_VERSION_ID >= 50400 - object_properties_init( (zend_object *) i_obj, ce); -#else - { - zval *tmp; - zend_hash_copy(i_obj->zo.properties, &ce->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); - } -#endif - - retval.handle = zend_objects_store_put(i_obj, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)php_memc_free_storage, NULL TSRMLS_CC); - retval.handlers = &memcached_object_handlers; - - return retval; + php_memc_t *i_obj = ecalloc(1, sizeof(php_memc_t) + sizeof(zval) * (ce->default_properties_count - 1)); + + zend_object_std_init(&i_obj->zo, ce); + object_properties_init(&i_obj->zo, ce); + + i_obj->zo.handlers = &memcached_object_handlers; + + return &i_obj->zo; } #ifdef HAVE_MEMCACHED_PROTOCOL static -void php_memc_server_free_storage(php_memc_server_t *intern TSRMLS_DC) +void php_memc_server_free_storage(php_memc_server_t *intern) { - zend_object_std_dtor(&intern->zo TSRMLS_CC); + zend_object_std_dtor(&intern->zo); efree (intern); } -zend_object_value php_memc_server_new(zend_class_entry *ce TSRMLS_DC) +zend_object_value php_memc_server_new(zend_class_entry *ce) { zend_object_value retval; php_memc_server_t *intern; zval *tmp; intern = ecalloc(1, sizeof(php_memc_server_t)); - zend_object_std_init (&intern->zo, ce TSRMLS_CC); + zend_object_std_init (&intern->zo, ce); #if PHP_VERSION_ID >= 50400 object_properties_init( (zend_object *) intern, ce); #else @@ -2915,7 +2856,7 @@ zend_object_value php_memc_server_new(zend_class_entry *ce TSRMLS_DC) intern->handler = php_memc_proto_handler_new (); - retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)php_memc_server_free_storage, NULL TSRMLS_CC); + retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)php_memc_server_free_storage, NULL); retval.handlers = &memcached_server_object_handlers; return retval; @@ -2924,20 +2865,20 @@ zend_object_value php_memc_server_new(zend_class_entry *ce TSRMLS_DC) ZEND_RSRC_DTOR_FUNC(php_memc_dtor) { - if (rsrc->ptr) { - struct memc_obj *m_obj = (struct memc_obj *)rsrc->ptr; - php_memc_destroy(m_obj, 1 TSRMLS_CC); - rsrc->ptr = NULL; + if (res->ptr) { + struct memc_obj *m_obj = (struct memc_obj *)res->ptr; + php_memc_destroy(m_obj, 1); + res->ptr = NULL; } } ZEND_RSRC_DTOR_FUNC(php_memc_sess_dtor) { - if (rsrc->ptr) { - memcached_sess *memc_sess = (memcached_sess *)rsrc->ptr; + if (res->ptr) { + memcached_sess *memc_sess = (memcached_sess *)res->ptr; memcached_free(memc_sess->memc_sess); - pefree(rsrc->ptr, 1); - rsrc->ptr = NULL; + pefree(res->ptr, 1); + res->ptr = NULL; } } /* }}} */ @@ -2946,18 +2887,17 @@ ZEND_RSRC_DTOR_FUNC(php_memc_sess_dtor) static memcached_return php_memc_do_serverlist_callback(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context) { struct callbackContext* context = (struct callbackContext*) in_context; - zval *array; + zval array; - MAKE_STD_ZVAL(array); - array_init(array); - add_assoc_string(array, "host", (char*) memcached_server_name(instance), 1); - add_assoc_long(array, "port", memcached_server_port(instance)); + array_init(&array); + add_assoc_string(&array, "host", (char*) memcached_server_name(instance)); + add_assoc_long(&array, "port", memcached_server_port(instance)); /* * API does not allow to get at this field. add_assoc_long(array, "weight", instance->weight); */ - add_next_index_zval(context->return_value, array); + add_next_index_zval(context->return_value, &array); return MEMCACHED_SUCCESS; } @@ -2966,38 +2906,37 @@ static memcached_return php_memc_do_stats_callback(const memcached_st *ptr, php_ char *hostport = NULL; int hostport_len; struct callbackContext* context = (struct callbackContext*) in_context; - zval *entry; - hostport_len = spprintf(&hostport, 0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance)); - - MAKE_STD_ZVAL(entry); - array_init(entry); - - add_assoc_long(entry, "pid", context->stats[context->i].pid); - add_assoc_long(entry, "uptime", context->stats[context->i].uptime); - add_assoc_long(entry, "threads", context->stats[context->i].threads); - add_assoc_long(entry, "time", context->stats[context->i].time); - add_assoc_long(entry, "pointer_size", context->stats[context->i].pointer_size); - add_assoc_long(entry, "rusage_user_seconds", context->stats[context->i].rusage_user_seconds); - add_assoc_long(entry, "rusage_user_microseconds", context->stats[context->i].rusage_user_microseconds); - add_assoc_long(entry, "rusage_system_seconds", context->stats[context->i].rusage_system_seconds); - add_assoc_long(entry, "rusage_system_microseconds", context->stats[context->i].rusage_system_microseconds); - add_assoc_long(entry, "curr_items", context->stats[context->i].curr_items); - add_assoc_long(entry, "total_items", context->stats[context->i].total_items); - add_assoc_long(entry, "limit_maxbytes", context->stats[context->i].limit_maxbytes); - add_assoc_long(entry, "curr_connections", context->stats[context->i].curr_connections); - add_assoc_long(entry, "total_connections", context->stats[context->i].total_connections); - add_assoc_long(entry, "connection_structures", context->stats[context->i].connection_structures); - add_assoc_long(entry, "bytes", context->stats[context->i].bytes); - add_assoc_long(entry, "cmd_get", context->stats[context->i].cmd_get); - add_assoc_long(entry, "cmd_set", context->stats[context->i].cmd_set); - add_assoc_long(entry, "get_hits", context->stats[context->i].get_hits); - add_assoc_long(entry, "get_misses", context->stats[context->i].get_misses); - add_assoc_long(entry, "evictions", context->stats[context->i].evictions); - add_assoc_long(entry, "bytes_read", context->stats[context->i].bytes_read); - add_assoc_long(entry, "bytes_written", context->stats[context->i].bytes_written); - add_assoc_stringl(entry, "version", context->stats[context->i].version, strlen(context->stats[context->i].version), 1); - - add_assoc_zval_ex(context->return_value, hostport, hostport_len+1, entry); + zval entry; + hostport_len = spprintf(&hostport, 0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance) - 1); + + array_init(&entry); + + add_assoc_long(&entry, "pid", context->stats[context->i].pid); + add_assoc_long(&entry, "uptime", context->stats[context->i].uptime); + add_assoc_long(&entry, "threads", context->stats[context->i].threads); + add_assoc_long(&entry, "time", context->stats[context->i].time); + add_assoc_long(&entry, "pointer_size", context->stats[context->i].pointer_size); + add_assoc_long(&entry, "rusage_user_seconds", context->stats[context->i].rusage_user_seconds); + add_assoc_long(&entry, "rusage_user_microseconds", context->stats[context->i].rusage_user_microseconds); + add_assoc_long(&entry, "rusage_system_seconds", context->stats[context->i].rusage_system_seconds); + add_assoc_long(&entry, "rusage_system_microseconds", context->stats[context->i].rusage_system_microseconds); + add_assoc_long(&entry, "curr_items", context->stats[context->i].curr_items); + add_assoc_long(&entry, "total_items", context->stats[context->i].total_items); + add_assoc_long(&entry, "limit_maxbytes", context->stats[context->i].limit_maxbytes); + add_assoc_long(&entry, "curr_connections", context->stats[context->i].curr_connections); + add_assoc_long(&entry, "total_connections", context->stats[context->i].total_connections); + add_assoc_long(&entry, "connection_structures", context->stats[context->i].connection_structures); + add_assoc_long(&entry, "bytes", context->stats[context->i].bytes); + add_assoc_long(&entry, "cmd_get", context->stats[context->i].cmd_get); + add_assoc_long(&entry, "cmd_set", context->stats[context->i].cmd_set); + add_assoc_long(&entry, "get_hits", context->stats[context->i].get_hits); + add_assoc_long(&entry, "get_misses", context->stats[context->i].get_misses); + add_assoc_long(&entry, "evictions", context->stats[context->i].evictions); + add_assoc_long(&entry, "bytes_read", context->stats[context->i].bytes_read); + add_assoc_long(&entry, "bytes_written", context->stats[context->i].bytes_written); + add_assoc_stringl(&entry, "version", context->stats[context->i].version, strlen(context->stats[context->i].version)); + + add_assoc_zval_ex(context->return_value, hostport, hostport_len+1, &entry); efree(hostport); /* Increment the server count in our context structure. Failure to do so will cause only the stats for the last server to get displayed. */ @@ -3012,7 +2951,7 @@ static memcached_return php_memc_do_version_callback(const memcached_st *ptr, ph int hostport_len, version_len; struct callbackContext* context = (struct callbackContext*) in_context; - hostport_len = spprintf(&hostport, 0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance)); + hostport_len = spprintf(&hostport, 0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance) - 1); #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x01000009 version_len = snprintf(version, sizeof(version), "%d.%d.%d", memcached_server_major_version(instance), @@ -3025,12 +2964,12 @@ static memcached_return php_memc_do_version_callback(const memcached_st *ptr, ph instance->micro_version); #endif - add_assoc_stringl_ex(context->return_value, hostport, hostport_len+1, version, version_len, 1); + add_assoc_stringl_ex(context->return_value, hostport, hostport_len+1, version, version_len); efree(hostport); return MEMCACHED_SUCCESS; } -static int php_memc_handle_error(php_memc_t *i_obj, memcached_return status TSRMLS_DC) +static int php_memc_handle_error(php_memc_t *i_obj, memcached_return status) { int result = 0; @@ -3077,7 +3016,7 @@ static int php_memc_handle_error(php_memc_t *i_obj, memcached_return status TSRM } static -char *s_compress_value (enum memcached_compression_type compression_type, const char *payload, size_t *payload_len, uint32_t *flags TSRMLS_DC) +char *s_compress_value (enum memcached_compression_type compression_type, const char *payload, size_t *payload_len, uint32_t *flags) { /* status */ zend_bool compress_status = 0; @@ -3117,7 +3056,7 @@ char *s_compress_value (enum memcached_compression_type compression_type, const *payload_len = compressed_size + sizeof(uint32_t); if (!compress_status) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not compress value"); + php_error_docref(NULL, E_WARNING, "could not compress value"); MEMC_VAL_DEL_FLAG(*flags, MEMC_VAL_COMPRESSED); efree (buffer); @@ -3135,7 +3074,7 @@ char *s_compress_value (enum memcached_compression_type compression_type, const } static -zend_bool s_serialize_value (enum memcached_serializer serializer, zval *value, smart_str *buf, uint32_t *flags TSRMLS_DC) +zend_bool s_serialize_value (enum memcached_serializer serializer, zval *value, smart_str *buf, uint32_t *flags) { switch (serializer) { @@ -3144,8 +3083,8 @@ zend_bool s_serialize_value (enum memcached_serializer serializer, zval *value, */ #ifdef HAVE_MEMCACHED_IGBINARY case SERIALIZER_IGBINARY: - if (igbinary_serialize((uint8_t **) &buf->c, &buf->len, value TSRMLS_CC) != 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not serialize value with igbinary"); + if (igbinary_serialize((uint8_t **) &buf->c, &buf->len, value) != 0) { + php_error_docref(NULL, E_WARNING, "could not serialize value with igbinary"); return 0; } MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_IGBINARY); @@ -3160,9 +3099,9 @@ zend_bool s_serialize_value (enum memcached_serializer serializer, zval *value, case SERIALIZER_JSON_ARRAY: { #if HAVE_JSON_API_5_2 - php_json_encode(buf, value TSRMLS_CC); + php_json_encode(buf, value); #elif HAVE_JSON_API_5_3 - php_json_encode(buf, value, 0 TSRMLS_CC); /* options */ + php_json_encode(buf, value, 0); /* options */ #endif MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_JSON); } @@ -3174,9 +3113,9 @@ zend_bool s_serialize_value (enum memcached_serializer serializer, zval *value, */ #ifdef HAVE_MEMCACHED_MSGPACK case SERIALIZER_MSGPACK: - php_msgpack_serialize(buf, value TSRMLS_CC); + php_msgpack_serialize(buf, value); if (!buf->c) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not serialize value with msgpack"); + php_error_docref(NULL, E_WARNING, "could not serialize value with msgpack"); return 0; } MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_MSGPACK); @@ -3190,11 +3129,11 @@ zend_bool s_serialize_value (enum memcached_serializer serializer, zval *value, { php_serialize_data_t var_hash; PHP_VAR_SERIALIZE_INIT(var_hash); - php_var_serialize(buf, &value, &var_hash TSRMLS_CC); + php_var_serialize(buf, value, &var_hash); PHP_VAR_SERIALIZE_DESTROY(var_hash); - if (!buf->c) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not serialize value"); + if (!buf->s) { + php_error_docref(NULL, E_WARNING, "could not serialize value"); return 0; } MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_SERIALIZED); @@ -3203,14 +3142,14 @@ zend_bool s_serialize_value (enum memcached_serializer serializer, zval *value, } /* Check for exceptions caused by serializers */ - if (EG(exception) && buf->len) { + if (EG(exception) && buf->s->len) { return 0; } return 1; } static -char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t *flags, enum memcached_serializer serializer, enum memcached_compression_type compression_type TSRMLS_DC) +char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t *flags, enum memcached_serializer serializer, enum memcached_compression_type compression_type) { const char *pl; size_t pl_len = 0; @@ -3240,26 +3179,28 @@ char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t *flags MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_DOUBLE); break; - case IS_BOOL: - if (Z_BVAL_P(value)) { - pl_len = 1; - tmp[0] = '1'; - tmp[1] = '\0'; - } else { - pl_len = 0; - tmp[0] = '\0'; - } + case IS_TRUE: + pl_len = 1; + tmp[0] = '1'; + tmp[1] = '\0'; + pl = tmp; + MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_BOOL); + break; + + case IS_FALSE: + pl_len = 0; + tmp[0] = '\0'; pl = tmp; MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_BOOL); break; default: - if (!s_serialize_value (serializer, value, &buf, flags TSRMLS_CC)) { + if (!s_serialize_value (serializer, value, &buf, flags)) { smart_str_free (&buf); return NULL; } - pl = buf.c; - pl_len = buf.len; + pl = buf.s->val; + pl_len = buf.s->len; break; } @@ -3272,7 +3213,7 @@ char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t *flags if (MEMC_VAL_HAS_FLAG(*flags, MEMC_VAL_COMPRESSED)) { /* status */ *payload_len = pl_len; - payload = s_compress_value (compression_type, pl, payload_len, flags TSRMLS_CC); + payload = s_compress_value (compression_type, pl, payload_len, flags); } /* If compression failed or value is below threshold we just use plain value */ @@ -3281,14 +3222,14 @@ char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t *flags payload = estrndup(pl, pl_len); } - if (buf.len) { + if (buf.s) { smart_str_free(&buf); } return payload; } static -char *s_decompress_value (const char *payload, size_t *payload_len, uint32_t flags TSRMLS_DC) +char *s_decompress_value (const char *payload, size_t *payload_len, uint32_t flags) { char *buffer = NULL; uint32_t len; @@ -3329,7 +3270,7 @@ char *s_decompress_value (const char *payload, size_t *payload_len, uint32_t fla } if (!decompress_status) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not decompress value"); + php_error_docref(NULL, E_WARNING, "could not decompress value"); efree(buffer); return NULL; } @@ -3339,7 +3280,7 @@ char *s_decompress_value (const char *payload, size_t *payload_len, uint32_t fla } static -zend_bool s_unserialize_value (enum memcached_serializer serializer, int val_type, zval *value, const char *payload, size_t payload_len TSRMLS_DC) +zend_bool s_unserialize_value (enum memcached_serializer serializer, int val_type, zval *value, const char *payload, size_t payload_len) { switch (val_type) { case MEMC_VAL_IS_SERIALIZED: @@ -3348,10 +3289,10 @@ zend_bool s_unserialize_value (enum memcached_serializer serializer, int val_typ php_unserialize_data_t var_hash; PHP_VAR_UNSERIALIZE_INIT(var_hash); - if (!php_var_unserialize(&value, (const unsigned char **)&payload_tmp, (const unsigned char *)payload_tmp + payload_len, &var_hash TSRMLS_CC)) { + if (!php_var_unserialize(value, (const unsigned char **)&payload_tmp, (const unsigned char *)payload_tmp + payload_len, &var_hash)) { ZVAL_FALSE(value); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); - php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value"); + php_error_docref(NULL, E_WARNING, "could not unserialize value"); return 0; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); @@ -3360,14 +3301,14 @@ zend_bool s_unserialize_value (enum memcached_serializer serializer, int val_typ case MEMC_VAL_IS_IGBINARY: #ifdef HAVE_MEMCACHED_IGBINARY - if (igbinary_unserialize((uint8_t *)payload, payload_len, &value TSRMLS_CC)) { + if (igbinary_unserialize((uint8_t *)payload, payload_len, &value)) { ZVAL_FALSE(value); - php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value with igbinary"); + php_error_docref(NULL, E_WARNING, "could not unserialize value with igbinary"); return 0; } #else ZVAL_FALSE(value); - php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value, no igbinary support"); + php_error_docref(NULL, E_WARNING, "could not unserialize value, no igbinary support"); return 0; #endif break; @@ -3375,23 +3316,23 @@ zend_bool s_unserialize_value (enum memcached_serializer serializer, int val_typ case MEMC_VAL_IS_JSON: #ifdef HAVE_JSON_API # if HAVE_JSON_API_5_2 - php_json_decode(value, payload, payload_len, (serializer == SERIALIZER_JSON_ARRAY) TSRMLS_CC); + php_json_decode(value, payload, payload_len, (serializer == SERIALIZER_JSON_ARRAY)); # elif HAVE_JSON_API_5_3 - php_json_decode(value, payload, payload_len, (serializer == SERIALIZER_JSON_ARRAY), JSON_PARSER_DEFAULT_DEPTH TSRMLS_CC); + php_json_decode(value, payload, payload_len, (serializer == SERIALIZER_JSON_ARRAY), JSON_PARSER_DEFAULT_DEPTH); # endif #else ZVAL_FALSE(value); - php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value, no json support"); + php_error_docref(NULL, E_WARNING, "could not unserialize value, no json support"); return 0; #endif break; case MEMC_VAL_IS_MSGPACK: #ifdef HAVE_MEMCACHED_MSGPACK - php_msgpack_unserialize(value, payload, payload_len TSRMLS_CC); + php_msgpack_unserialize(value, payload, payload_len); #else ZVAL_FALSE(value); - php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value, no msgpack support"); + php_error_docref(NULL, E_WARNING, "could not unserialize value, no msgpack support"); return 0; #endif break; @@ -3400,7 +3341,7 @@ zend_bool s_unserialize_value (enum memcached_serializer serializer, int val_typ } /* The caller MUST free the payload */ -static int php_memc_zval_from_payload(zval *value, const char *payload_in, size_t payload_len, uint32_t flags, enum memcached_serializer serializer TSRMLS_DC) +static int php_memc_zval_from_payload(zval *value, const char *payload_in, size_t payload_len, uint32_t flags, enum memcached_serializer serializer) { /* A NULL payload is completely valid if length is 0, it is simply empty. @@ -3411,7 +3352,7 @@ static int php_memc_zval_from_payload(zval *value, const char *payload_in, size_ if (payload_in == NULL && payload_len > 0) { ZVAL_FALSE(value); - php_error_docref(NULL TSRMLS_CC, E_WARNING, + php_error_docref(NULL, E_WARNING, "Could not handle non-existing value of length %zu", payload_len); return -1; } else if (payload_in == NULL) { @@ -3424,7 +3365,7 @@ static int php_memc_zval_from_payload(zval *value, const char *payload_in, size_ } if (MEMC_VAL_HAS_FLAG(flags, MEMC_VAL_COMPRESSED)) { - char *datas = s_decompress_value (payload_in, &payload_len, flags TSRMLS_CC); + char *datas = s_decompress_value (payload_in, &payload_len, flags); if (!datas) { ZVAL_FALSE(value); return -1; @@ -3438,10 +3379,10 @@ static int php_memc_zval_from_payload(zval *value, const char *payload_in, size_ switch (MEMC_VAL_GET_TYPE(flags)) { case MEMC_VAL_IS_STRING: if (payload_emalloc) { - ZVAL_STRINGL(value, pl, payload_len, 0); + ZVAL_STRINGL(value, pl, payload_len); payload_emalloc = 0; } else { - ZVAL_STRINGL(value, pl, payload_len, 1); + ZVAL_STRINGL(value, pl, payload_len); } break; @@ -3451,7 +3392,7 @@ static int php_memc_zval_from_payload(zval *value, const char *payload_in, size_ char conv_buf [128]; if (payload_len >= 128) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not read long value, too big"); + php_error_docref(NULL, E_WARNING, "could not read long value, too big"); retval = -1; } else { @@ -3469,7 +3410,7 @@ static int php_memc_zval_from_payload(zval *value, const char *payload_in, size_ char conv_buf [128]; if (payload_len >= 128) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not read double value, too big"); + php_error_docref(NULL, E_WARNING, "could not read double value, too big"); retval = -1; } else { @@ -3497,14 +3438,14 @@ static int php_memc_zval_from_payload(zval *value, const char *payload_in, size_ case MEMC_VAL_IS_IGBINARY: case MEMC_VAL_IS_JSON: case MEMC_VAL_IS_MSGPACK: - if (!s_unserialize_value (serializer, MEMC_VAL_GET_TYPE(flags), value, pl, payload_len TSRMLS_CC)) { + if (!s_unserialize_value (serializer, MEMC_VAL_GET_TYPE(flags), value, pl, payload_len)) { retval = -1; } break; default: ZVAL_FALSE(value); - php_error_docref(NULL TSRMLS_CC, E_WARNING, "unknown payload type"); + php_error_docref(NULL, E_WARNING, "unknown payload type"); retval = -1; break; } @@ -3528,17 +3469,20 @@ zend_class_entry *php_memc_get_exception(void) } PHP_MEMCACHED_API -zend_class_entry *php_memc_get_exception_base(int root TSRMLS_DC) +zend_class_entry *php_memc_get_exception_base(int root) { #if HAVE_SPL if (!root) { if (!spl_ce_RuntimeException) { - zend_class_entry **pce; - - if (zend_hash_find(CG(class_table), "runtimeexception", - sizeof("RuntimeException"), (void **) &pce) == SUCCESS) { - spl_ce_RuntimeException = *pce; - return *pce; + zend_class_entry *pce; + zval *pce_z; + + if ((pce_z = zend_hash_str_find(CG(class_table), + "runtimeexception", + sizeof("RuntimeException") - 1)) != NULL) { + pce = Z_CE_P(pce_z); + spl_ce_RuntimeException = pce; + return pce; } } else { return spl_ce_RuntimeException; @@ -3548,20 +3492,19 @@ zend_class_entry *php_memc_get_exception_base(int root TSRMLS_DC) #if (PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION < 2) return zend_exception_get_default(); #else - return zend_exception_get_default(TSRMLS_C); + return zend_exception_get_default(); #endif } static memcached_return php_memc_do_cache_callback(zval *zmemc_obj, zend_fcall_info *fci, - zend_fcall_info_cache *fcc, char *key, - size_t key_len, zval *value TSRMLS_DC) + zend_fcall_info_cache *fcc, zend_string *key, zval *value) { char *payload = NULL; size_t payload_len = 0; - zval **params[4]; - zval *retval; - zval *z_key; - zval *z_expiration; + zval params[4]; + zval retval; + zval z_key; + zval z_expiration; uint32_t flags = 0; memcached_return rc; @@ -3569,40 +3512,38 @@ static memcached_return php_memc_do_cache_callback(zval *zmemc_obj, zend_fcall_i memcached_return status = MEMCACHED_SUCCESS; int result; - MAKE_STD_ZVAL(z_key); - MAKE_STD_ZVAL(z_expiration); - ZVAL_STRINGL(z_key, key, key_len, 1); + ZVAL_STR(&z_key, key); ZVAL_NULL(value); - ZVAL_LONG(z_expiration, 0); + ZVAL_LONG(&z_expiration, 0); - params[0] = &zmemc_obj; - params[1] = &z_key; - params[2] = &value; - params[3] = &z_expiration; + ZVAL_COPY(¶ms[0], zmemc_obj); + ZVAL_COPY(¶ms[1], &z_key); + ZVAL_COPY(¶ms[2], value); + ZVAL_COPY(¶ms[3], &z_expiration); - fci->retval_ptr_ptr = &retval; + fci->retval = &retval; fci->params = params; - fci->param_count = sizeof(params) / sizeof(params[0]); + fci->param_count = 4; - result = zend_call_function(fci, fcc TSRMLS_CC); - if (result == SUCCESS && retval) { - i_obj = (php_memc_t *) zend_object_store_get_object(zmemc_obj TSRMLS_CC); + result = zend_call_function(fci, fcc); + if (result == SUCCESS && Z_TYPE(retval) != IS_UNDEF) { + i_obj = (php_memc_t *) Z_OBJ_P(zmemc_obj); struct memc_obj *m_obj = i_obj->obj; - if (zend_is_true(retval)) { + if (zend_is_true(&retval)) { time_t expiration; - if (Z_TYPE_P(z_expiration) != IS_LONG) { - convert_to_long(z_expiration); + if (Z_TYPE(z_expiration) != IS_LONG) { + convert_to_long(&z_expiration); } - expiration = Z_LVAL_P(z_expiration); + expiration = Z_LVAL(z_expiration); - payload = php_memc_zval_to_payload(value, &payload_len, &flags, m_obj->serializer, m_obj->compression_type TSRMLS_CC); + payload = php_memc_zval_to_payload(value, &payload_len, &flags, m_obj->serializer, m_obj->compression_type); if (payload == NULL) { status = (memcached_return)MEMC_RES_PAYLOAD_FAILURE; } else { - rc = memcached_set(m_obj->memc, key, key_len, payload, payload_len, expiration, flags); + rc = memcached_set(m_obj->memc, key->val, key->len, payload, payload_len, expiration, flags); if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED) { status = rc; } @@ -3616,14 +3557,16 @@ static memcached_return php_memc_do_cache_callback(zval *zmemc_obj, zend_fcall_i } else { if (result == FAILURE) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not invoke cache callback"); + zval_ptr_dtor(&z_key); + zval_ptr_dtor(&z_expiration); + php_error_docref(NULL, E_WARNING, "could not invoke cache callback"); } status = MEMCACHED_FAILURE; zval_dtor(value); ZVAL_NULL(value); } - if (retval) { + if (&retval) { zval_ptr_dtor(&retval); } @@ -3635,24 +3578,23 @@ static memcached_return php_memc_do_cache_callback(zval *zmemc_obj, zend_fcall_i static int php_memc_do_result_callback(zval *zmemc_obj, zend_fcall_info *fci, zend_fcall_info_cache *fcc, - memcached_result_st *result TSRMLS_DC) + memcached_result_st *result) { const char *res_key = NULL; size_t res_key_len = 0; const char *payload = NULL; size_t payload_len = 0; - zval *value, *retval = NULL; + zval value; + zval retval; uint64_t cas = 0; - zval **params[2]; - zval *z_result; + zval params[2]; + zval z_result; uint32_t flags = 0; int rc = 0; php_memc_t *i_obj = NULL; - params[0] = &zmemc_obj; - params[1] = &z_result; - - fci->retval_ptr_ptr = &retval; + ZVAL_COPY(¶ms[0], zmemc_obj); + fci->retval = &retval; fci->params = params; fci->param_count = 2; @@ -3663,35 +3605,35 @@ static int php_memc_do_result_callback(zval *zmemc_obj, zend_fcall_info *fci, res_key_len = memcached_result_key_length(result); cas = memcached_result_cas(result); - ALLOC_INIT_ZVAL(value); - - i_obj = (php_memc_t *) zend_object_store_get_object(zmemc_obj TSRMLS_CC); + i_obj = Z_MEMC_OBJ_P(zmemc_obj); - if (php_memc_zval_from_payload(value, payload, payload_len, flags, i_obj->obj->serializer TSRMLS_CC) < 0) { + if (php_memc_zval_from_payload(&value, payload, payload_len, flags, i_obj->obj->serializer) < 0) { zval_ptr_dtor(&value); i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE; return -1; } - MAKE_STD_ZVAL(z_result); - array_init(z_result); - add_assoc_stringl_ex(z_result, ZEND_STRS("key"), res_key, res_key_len, 1); - add_assoc_zval_ex(z_result, ZEND_STRS("value"), value); + array_init(&z_result); + ZVAL_COPY(¶ms[1], &z_result); + add_assoc_stringl_ex(&z_result, ZEND_STRL("key"), (char *)res_key, res_key_len); + add_assoc_zval_ex(&z_result, ZEND_STRL("value"), &value); if (cas != 0) { - add_assoc_double_ex(z_result, ZEND_STRS("cas"), (double)cas); + add_assoc_double_ex(&z_result, ZEND_STRL("cas"), (double)cas); } if (MEMC_VAL_GET_USER_FLAGS(flags) != 0) { - add_assoc_long_ex(z_result, ZEND_STRS("flags"), MEMC_VAL_GET_USER_FLAGS(flags)); + add_assoc_long_ex(&z_result, ZEND_STRL("flags"), MEMC_VAL_GET_USER_FLAGS(flags)); } - if (zend_call_function(fci, fcc TSRMLS_CC) == FAILURE) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not invoke result callback"); + if (zend_call_function(fci, fcc) == FAILURE) { + php_error_docref(NULL, E_WARNING, "could not invoke result callback"); rc = -1; } - if (retval) { + if (&retval) { zval_ptr_dtor(&retval); } + zval_ptr_dtor(¶ms[0]); + zval_ptr_dtor(¶ms[1]); zval_ptr_dtor(&z_result); return rc; @@ -3716,13 +3658,12 @@ PHP_METHOD(MemcachedServer, run) { int i; zend_bool rc; - char *address; - int address_len; + zend *address; php_memc_server_t *intern; - intern = (php_memc_server_t *) zend_object_store_get_object(getThis() TSRMLS_CC); + intern = Z_MEMC_OBJ_P(getThis()); - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &address, &address_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &address) == FAILURE) { return; } @@ -3743,7 +3684,7 @@ PHP_METHOD(MemcachedServer, on) zend_fcall_info_cache fci_cache; zend_bool rc = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lf!", &event, &fci, &fci_cache) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "lf!", &event, &fci, &fci_cache) == FAILURE) { return; } @@ -4245,9 +4186,9 @@ zend_module_entry memcached_module_entry = { /* {{{ php_memc_register_constants */ static void php_memc_register_constants(INIT_FUNC_ARGS) { - #define REGISTER_MEMC_CLASS_CONST_LONG(name, value) zend_declare_class_constant_long(php_memc_get_ce() , ZEND_STRS( #name ) - 1, value TSRMLS_CC) - #define REGISTER_MEMC_CLASS_CONST_BOOL(name, value) zend_declare_class_constant_bool(php_memc_get_ce() , ZEND_STRS( #name ) - 1, value TSRMLS_CC) - #define REGISTER_MEMC_CLASS_CONST_NULL(name) zend_declare_class_constant_null(php_memc_get_ce() , ZEND_STRS( #name ) - 1 TSRMLS_CC) + #define REGISTER_MEMC_CLASS_CONST_LONG(name, value) zend_declare_class_constant_long(php_memc_get_ce() , ZEND_STRS( #name ) - 1, value) + #define REGISTER_MEMC_CLASS_CONST_BOOL(name, value) zend_declare_class_constant_bool(php_memc_get_ce() , ZEND_STRS( #name ) - 1, value) + #define REGISTER_MEMC_CLASS_CONST_NULL(name) zend_declare_class_constant_null(php_memc_get_ce() , ZEND_STRS( #name ) - 1) /* * Class options @@ -4489,13 +4430,15 @@ PHP_MINIT_FUNCTION(memcached) zend_class_entry ce; memcpy(&memcached_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + memcached_object_handlers.offset = XtOffsetOf(php_memc_t, zo); memcached_object_handlers.clone_obj = NULL; + memcached_object_handlers.free_obj = php_memc_free_storage; le_memc = zend_register_list_destructors_ex(NULL, php_memc_dtor, "Memcached persistent connection", module_number); le_memc_sess = zend_register_list_destructors_ex(NULL, php_memc_sess_dtor, "Memcached Sessions persistent connection", module_number); INIT_CLASS_ENTRY(ce, "Memcached", memcached_class_methods); - memcached_ce = zend_register_internal_class(&ce TSRMLS_CC); + memcached_ce = zend_register_internal_class(&ce); memcached_ce->create_object = php_memc_new; #ifdef HAVE_MEMCACHED_PROTOCOL @@ -4503,12 +4446,12 @@ PHP_MINIT_FUNCTION(memcached) memcached_server_object_handlers.clone_obj = NULL; INIT_CLASS_ENTRY(ce, "MemcachedServer", memcached_server_class_methods); - memcached_server_ce = zend_register_internal_class(&ce TSRMLS_CC); + memcached_server_ce = zend_register_internal_class(&ce); memcached_server_ce->create_object = php_memc_server_new; #endif INIT_CLASS_ENTRY(ce, "MemcachedException", NULL); - memcached_exception_ce = zend_register_internal_class_ex(&ce, php_memc_get_exception_base(0 TSRMLS_CC), NULL TSRMLS_CC); + memcached_exception_ce = zend_register_internal_class_ex(&ce, php_memc_get_exception_base(0)); /* TODO * possibly declare custom exception property here */ @@ -4523,7 +4466,7 @@ PHP_MINIT_FUNCTION(memcached) #if HAVE_MEMCACHED_SASL if (MEMC_G(use_sasl)) { if (sasl_client_init(NULL) != SASL_OK) { - php_error_docref(NULL TSRMLS_CC, E_ERROR, "Failed to initialize SASL library"); + php_error_docref(NULL, E_ERROR, "Failed to initialize SASL library"); return FAILURE; } } diff --git a/php_memcached.h b/php_memcached.h index bce8e37b..da4d6b92 100644 --- a/php_memcached.h +++ b/php_memcached.h @@ -36,7 +36,7 @@ PHP_MEMCACHED_API zend_class_entry *php_memc_get_ce(void); PHP_MEMCACHED_API zend_class_entry *php_memc_get_exception(void); -PHP_MEMCACHED_API zend_class_entry *php_memc_get_exception_base(int root TSRMLS_DC); +PHP_MEMCACHED_API zend_class_entry *php_memc_get_exception_base(int root); extern zend_module_entry memcached_module_entry; #define phpext_memcached_ptr &memcached_module_entry diff --git a/php_memcached_private.h b/php_memcached_private.h index 0ec2d76e..2929818e 100644 --- a/php_memcached_private.h +++ b/php_memcached_private.h @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include diff --git a/php_memcached_server.c b/php_memcached_server.c index 42ccc8ee..eb225db0 100644 --- a/php_memcached_server.c +++ b/php_memcached_server.c @@ -60,7 +60,7 @@ typedef struct { } php_memc_client_t; static -long s_invoke_php_callback (php_memc_server_cb_t *cb, zval ***params, ssize_t param_count TSRMLS_DC) +long s_invoke_php_callback (php_memc_server_cb_t *cb, zval ***params, ssize_t param_count) { long retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; zval *retval_ptr = NULL; @@ -72,9 +72,9 @@ long s_invoke_php_callback (php_memc_server_cb_t *cb, zval ***params, ssize_t pa cb->fci.no_separation = 1; cb->fci.retval_ptr_ptr = &retval_ptr; - if (zend_call_function(&(cb->fci), &(cb->fci_cache) TSRMLS_CC) == FAILURE) { - char *buf = php_memc_printable_func (&(cb->fci), &(cb->fci_cache) TSRMLS_CC); - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to invoke callback %s()", buf); + if (zend_call_function(&(cb->fci), &(cb->fci_cache)) == FAILURE) { + char *buf = php_memc_printable_func (&(cb->fci), &(cb->fci_cache)); + php_error_docref(NULL, E_WARNING, "Failed to invoke callback %s()", buf); efree (buf); } if (retval_ptr) { @@ -91,10 +91,8 @@ protocol_binary_response_status s_add_handler(const void *cookie, const void *ke uint32_t data_len, uint32_t flags, uint32_t exptime, uint64_t *result_cas) { protocol_binary_response_status retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; - zval *zcookie, *zkey, *zvalue, *zflags, *zexptime, *zresult_cas; - zval **params [6]; - - TSRMLS_FETCH(); + zval zcookie, zkey, zvalue, zflags, zexptime, zresult_cas; + zval params[6]; if (!MEMC_HAS_CB(MEMC_SERVER_ON_ADD)) { return retval; @@ -102,32 +100,29 @@ protocol_binary_response_status s_add_handler(const void *cookie, const void *ke MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); - MAKE_STD_ZVAL(zkey); - ZVAL_STRINGL(zkey, key, key_len, 1); - - MAKE_STD_ZVAL(zvalue); - ZVAL_STRINGL(zvalue, data, data_len, 1); - - MAKE_STD_ZVAL(zflags); - ZVAL_LONG(zflags, flags); - - MAKE_STD_ZVAL(zexptime); - ZVAL_LONG(zexptime, exptime); + ZVAL_STRINGL(&zkey, key, key_len); + ZVAL_STRINGL(&zvalue, data, data_len); + ZVAL_LONG(&zflags, flags); + ZVAL_LONG(&zexptime, exptime); + ZVAL_NULL(&zresult_cas); - MAKE_STD_ZVAL(zresult_cas); - ZVAL_NULL(zresult_cas); + ZVAL_COPY(¶ms[0], &zcookie); + ZVAL_COPY(¶ms[1], &zkey); + ZVAL_COPY(¶ms[2], &zvalue); + ZVAL_COPY(¶ms[3], &zflags); + ZVAL_COPY(¶ms[4], &zexptime); + ZVAL_COPY(¶ms[5], &zresult_cas); - params [0] = &zcookie; - params [1] = &zkey; - params [2] = &zvalue; - params [3] = &zflags; - params [4] = &zexptime; - params [5] = &zresult_cas; - - retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_ADD), params, 6 TSRMLS_CC); + retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_ADD), params, 6); MEMC_MAKE_RESULT_CAS(zresult_cas, *result_cas); + zval_ptr_dtor(¶ms[0]); + zval_ptr_dtor(¶ms[1]); + zval_ptr_dtor(¶ms[2]); + zval_ptr_dtor(¶ms[3]); + zval_ptr_dtor(¶ms[4]); + zval_ptr_dtor(¶ms[5]); zval_ptr_dtor (&zcookie); zval_ptr_dtor (&zkey); zval_ptr_dtor (&zvalue); @@ -143,10 +138,8 @@ protocol_binary_response_status s_append_prepend_handler (php_memc_event_t event const void *data, uint32_t data_len, uint64_t cas, uint64_t *result_cas) { protocol_binary_response_status retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; - zval *zcookie, *zkey, *zvalue, *zcas, *zresult_cas; - zval **params [5]; - - TSRMLS_FETCH(); + zval zcookie, zkey, zvalue, zcas, zresult_cas; + zval params[5]; if (!MEMC_HAS_CB(event)) { return retval; @@ -154,28 +147,26 @@ protocol_binary_response_status s_append_prepend_handler (php_memc_event_t event MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); - MAKE_STD_ZVAL(zkey); - ZVAL_STRINGL(zkey, key, key_len, 1); - - MAKE_STD_ZVAL(zvalue); - ZVAL_STRINGL(zvalue, data, data_len, 1); + ZVAL_STRINGL(&zkey, key, key_len); + ZVAL_STRINGL(&zvalue, data, data_len); + ZVAL_DOUBLE(&zcas, cas); + ZVAL_NULL(&zresult_cas); - MAKE_STD_ZVAL(zcas); - ZVAL_DOUBLE(zcas, cas); + ZVAL_COPY(¶ms[0], &zcookie); + ZVAL_COPY(¶ms[1], &zkey); + ZVAL_COPY(¶ms[2], &zvalue); + ZVAL_COPY(¶ms[3], &zcas); + ZVAL_COPY(¶ms[4], &zresult_cas); - MAKE_STD_ZVAL(zresult_cas); - ZVAL_NULL(zresult_cas); - - params [0] = &zcookie; - params [1] = &zkey; - params [2] = &zvalue; - params [3] = &zcas; - params [4] = &zresult_cas; - - retval = s_invoke_php_callback (&MEMC_GET_CB(event), params, 5 TSRMLS_CC); + retval = s_invoke_php_callback (&MEMC_GET_CB(event), params, 5); MEMC_MAKE_RESULT_CAS(zresult_cas, *result_cas); + zval_ptr_dtor(¶ms[0]); + zval_ptr_dtor(¶ms[1]); + zval_ptr_dtor(¶ms[2]); + zval_ptr_dtor(¶ms[3]); + zval_ptr_dtor(¶ms[4]); zval_ptr_dtor (&zcookie); zval_ptr_dtor (&zkey); zval_ptr_dtor (&zvalue); @@ -206,10 +197,8 @@ protocol_binary_response_status s_incr_decr_handler (php_memc_event_t event, con uint64_t initial, uint32_t expiration, uint64_t *result, uint64_t *result_cas) { protocol_binary_response_status retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; - zval *zcookie, *zkey, *zdelta, *zinital, *zexpiration, *zresult, *zresult_cas; - zval **params [7]; - - TSRMLS_FETCH(); + zval zcookie, zkey, zdelta, zinital, zexpiration, zresult, zresult_cas; + zval params[7]; if (!MEMC_HAS_CB(event)) { return retval; @@ -217,41 +206,37 @@ protocol_binary_response_status s_incr_decr_handler (php_memc_event_t event, con MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); - MAKE_STD_ZVAL(zkey); - ZVAL_STRINGL(zkey, key, key_len, 1); - - MAKE_STD_ZVAL(zdelta); - ZVAL_LONG(zdelta, (long) delta); - - MAKE_STD_ZVAL(zinital); - ZVAL_LONG(zinital, (long) initial); - - MAKE_STD_ZVAL(zexpiration); - ZVAL_LONG(zexpiration, (long) expiration); + ZVAL_STRINGL(&zkey, key, key_len); + ZVAL_LONG(&zdelta, (long) delta); + ZVAL_LONG(&zinital, (long) initial); + ZVAL_LONG(&zexpiration, (long) expiration); + ZVAL_LONG(&zresult, 0); + ZVAL_NULL(&zresult_cas); - MAKE_STD_ZVAL(zresult); - ZVAL_LONG(zresult, 0); + ZVAL_COPY(¶ms[0], &zcookie); + ZVAL_COPY(¶ms[1], &zkey); + ZVAL_COPY(¶ms[2], &zdelta); + ZVAL_COPY(¶ms[3], &zinital); + ZVAL_COPY(¶ms[4], &zexpiration); + ZVAL_COPY(¶ms[5], &zresult); + ZVAL_COPY(¶ms[6], &zresult_cas); - MAKE_STD_ZVAL(zresult_cas); - ZVAL_NULL(zresult_cas); + retval = s_invoke_php_callback (&MEMC_GET_CB(event), params, 7); - params [0] = &zcookie; - params [1] = &zkey; - params [2] = &zdelta; - params [3] = &zinital; - params [4] = &zexpiration; - params [5] = &zresult; - params [6] = &zresult_cas; - - retval = s_invoke_php_callback (&MEMC_GET_CB(event), params, 7 TSRMLS_CC); - - if (Z_TYPE_P(zresult) != IS_LONG) { - convert_to_long (zresult); + if (Z_TYPE(zresult) != IS_LONG) { + convert_to_long (&zresult); } - *result = (uint64_t) Z_LVAL_P(zresult); + *result = (uint64_t) Z_LVAL(zresult); MEMC_MAKE_RESULT_CAS(zresult_cas, *result_cas); + zval_ptr_dtor(¶ms[0]); + zval_ptr_dtor(¶ms[1]); + zval_ptr_dtor(¶ms[2]); + zval_ptr_dtor(¶ms[3]); + zval_ptr_dtor(¶ms[4]); + zval_ptr_dtor(¶ms[5]); + zval_ptr_dtor(¶ms[6]); zval_ptr_dtor (&zcookie); zval_ptr_dtor (&zkey); zval_ptr_dtor (&zdelta); @@ -284,10 +269,8 @@ protocol_binary_response_status s_delete_handler (const void *cookie, const void uint16_t key_len, uint64_t cas) { protocol_binary_response_status retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; - zval *zcookie, *zkey, *zcas; - zval **params [3]; - - TSRMLS_FETCH(); + zval zcookie, zkey, zcas; + zval params[3]; if (!MEMC_HAS_CB(MEMC_SERVER_ON_DELETE)) { return retval; @@ -295,21 +278,21 @@ protocol_binary_response_status s_delete_handler (const void *cookie, const void MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); - MAKE_STD_ZVAL(zkey); - ZVAL_STRINGL(zkey, key, key_len, 1); - - MAKE_STD_ZVAL(zcas); - ZVAL_DOUBLE(zcas, (double) cas); - - params [0] = &zcookie; - params [1] = &zkey; - params [2] = &zcas; - - retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_DELETE), params, 3 TSRMLS_CC); - - zval_ptr_dtor (&zcookie); - zval_ptr_dtor (&zkey); - zval_ptr_dtor (&zcas); + ZVAL_STRINGL(&zkey, key, key_len); + ZVAL_DOUBLE(&zcas, (double) cas); + + ZVAL_COPY(¶ms[0], &zcookie); + ZVAL_COPY(¶ms[1], &zkey); + ZVAL_COPY(¶ms[2], &zcas); + + retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_DELETE), params, 3); + + zval_ptr_dtor(¶ms[0]); + zval_ptr_dtor(¶ms[1]); + zval_ptr_dtor(¶ms[2]); + zval_ptr_dtor(&zcookie); + zval_ptr_dtor(&zkey); + zval_ptr_dtor(&zcas); return retval; } @@ -317,10 +300,8 @@ static protocol_binary_response_status s_flush_handler(const void *cookie, uint32_t when) { protocol_binary_response_status retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; - zval *zcookie, *zwhen; - zval **params [2]; - - TSRMLS_FETCH(); + zval zcookie, zwhen; + zval params[2]; if (!MEMC_HAS_CB(MEMC_SERVER_ON_FLUSH)) { return retval; @@ -328,16 +309,15 @@ protocol_binary_response_status s_flush_handler(const void *cookie, uint32_t whe MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); - MAKE_STD_ZVAL(zwhen); - ZVAL_LONG(zwhen, (long) when); - - params [0] = &zcookie; - params [1] = &zwhen; + ZVAL_COPY(¶ms[0], &zcookie); + ZVAL_COPY(¶ms[1], &zwhen) - retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_FLUSH), params, 2 TSRMLS_CC); + retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_FLUSH), params, 2); - zval_ptr_dtor (&zcookie); - zval_ptr_dtor (&zwhen); + zval_ptr_dtor(¶ms[0]); + zval_ptr_dtor(¶ms[1]); + zval_ptr_dtor(&zcookie); + zval_ptr_dtor(&zwhen); return retval; } @@ -346,10 +326,8 @@ protocol_binary_response_status s_get_handler (const void *cookie, const void *k memcached_binary_protocol_get_response_handler response_handler) { protocol_binary_response_status retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; - zval *zcookie, *zkey, *zvalue, *zflags, *zresult_cas; - zval **params [5]; - - TSRMLS_FETCH(); + zval zcookie, zkey, zvalue, zflags, zresult_cas; + zval params[5]; if (!MEMC_HAS_CB(MEMC_SERVER_ON_GET)) { return retval; @@ -357,52 +335,50 @@ protocol_binary_response_status s_get_handler (const void *cookie, const void *k MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); - MAKE_STD_ZVAL(zkey); - ZVAL_STRINGL(zkey, key, key_len, 1); - - MAKE_STD_ZVAL(zvalue); - ZVAL_NULL(zvalue); - - MAKE_STD_ZVAL(zflags); - ZVAL_NULL(zflags); - - MAKE_STD_ZVAL(zresult_cas); - ZVAL_NULL(zresult_cas); + ZVAL_COPY(¶ms[0], &zcookie); + ZVAL_COPY(¶ms[1], &zkey); + ZVAL_COPY(¶ms[2], &zvalue); + ZVAL_COPY(¶ms[3], &zflags); + ZVAL_COPY(¶ms[4], &zresult_cas); - params [0] = &zcookie; - params [1] = &zkey; - params [2] = &zvalue; - params [3] = &zflags; - params [4] = &zresult_cas; - - retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_GET), params, 5 TSRMLS_CC); + retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_GET), params, 5); /* Succeeded in getting the key */ if (retval == PROTOCOL_BINARY_RESPONSE_SUCCESS) { uint32_t flags = 0; uint64_t result_cas = 0; - if (Z_TYPE_P (zvalue) == IS_NULL) { - zval_ptr_dtor (&zcookie); - zval_ptr_dtor (&zkey); - zval_ptr_dtor (&zvalue); - zval_ptr_dtor (&zflags); - zval_ptr_dtor (&zresult_cas); + if (Z_TYPE(zvalue) == IS_NULL) { + zval_ptr_dtor(¶ms[0]); + zval_ptr_dtor(¶ms[1]); + zval_ptr_dtor(¶ms[2]); + zval_ptr_dtor(¶ms[3]); + zval_ptr_dtor(¶ms[4]); + zval_ptr_dtor(&zcookie); + zval_ptr_dtor(&zkey); + zval_ptr_dtor(&zvalue); + zval_ptr_dtor(&zflags); + zval_ptr_dtor(&zresult_cas); return PROTOCOL_BINARY_RESPONSE_KEY_ENOENT; } - if (Z_TYPE_P (zvalue) != IS_STRING) { - convert_to_string (zvalue); + if (Z_TYPE(zvalue) != IS_STRING) { + convert_to_string (&zvalue); } - if (Z_TYPE_P (zflags) == IS_LONG) { - flags = Z_LVAL_P (zflags); + if (Z_TYPE(zflags) == IS_LONG) { + flags = Z_LVAL(zflags); } MEMC_MAKE_RESULT_CAS(zresult_cas, result_cas); - retval = response_handler(cookie, key, key_len, Z_STRVAL_P(zvalue), Z_STRLEN_P(zvalue), flags, result_cas); + retval = response_handler(cookie, key, key_len, Z_STRVAL(zvalue), Z_STRLEN(zvalue), flags, result_cas); } + zval_ptr_dtor(¶ms[0]); + zval_ptr_dtor(¶ms[1]); + zval_ptr_dtor(¶ms[2]); + zval_ptr_dtor(¶ms[3]); + zval_ptr_dtor(¶ms[4]); zval_ptr_dtor (&zcookie); zval_ptr_dtor (&zkey); zval_ptr_dtor (&zvalue); @@ -415,10 +391,8 @@ static protocol_binary_response_status s_noop_handler(const void *cookie) { protocol_binary_response_status retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; - zval *zcookie; - zval **params [1]; - - TSRMLS_FETCH(); + zval zcookie; + zval params[1]; if (!MEMC_HAS_CB(MEMC_SERVER_ON_NOOP)) { return retval; @@ -426,10 +400,11 @@ protocol_binary_response_status s_noop_handler(const void *cookie) MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); - params [0] = &zcookie; + ZVAL_COPY(¶ms[0], &zcookie); - retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_NOOP), params, 1 TSRMLS_CC); + retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_NOOP), params, 1); + zval_ptr_dtor(¶ms[0]); zval_ptr_dtor (&zcookie); return retval; } @@ -437,11 +412,9 @@ protocol_binary_response_status s_noop_handler(const void *cookie) static protocol_binary_response_status s_quit_handler(const void *cookie) { - zval **params [1]; + zval params[1]; protocol_binary_response_status retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; - zval *zcookie; - - TSRMLS_FETCH(); + zval zcookie; if (!MEMC_HAS_CB(MEMC_SERVER_ON_QUIT)) { return retval; @@ -449,9 +422,11 @@ protocol_binary_response_status s_quit_handler(const void *cookie) MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); - params [0] = &zcookie; - retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_QUIT), params, 1 TSRMLS_CC); + ZVAL_COPY(¶ms[0], &zcookie); + retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_QUIT), params, 1); + + zval_ptr_dtor(¶ms[0]); zval_ptr_dtor (&zcookie); return retval; } @@ -463,10 +438,8 @@ protocol_binary_response_status s_set_replace_handler (php_memc_event_t event, c uint32_t data_len, uint32_t flags, uint32_t expiration, uint64_t cas, uint64_t *result_cas) { protocol_binary_response_status retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; - zval *zcookie, *zkey, *zdata, *zflags, *zexpiration, *zcas, *zresult_cas; - zval **params [7]; - - TSRMLS_FETCH(); + zval zcookie, zkey, zdata, zflags, zexpiration, zcas, zresult_cas; + zval params[7]; if (!MEMC_HAS_CB(event)) { return retval; @@ -474,36 +447,32 @@ protocol_binary_response_status s_set_replace_handler (php_memc_event_t event, c MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); - MAKE_STD_ZVAL(zkey); - ZVAL_STRINGL(zkey, key, key_len, 1); - - MAKE_STD_ZVAL(zdata); - ZVAL_STRINGL(zdata, ((char *) data), (int) data_len, 1); - - MAKE_STD_ZVAL(zflags); - ZVAL_LONG(zflags, (long) flags); - - MAKE_STD_ZVAL(zexpiration); - ZVAL_LONG(zexpiration, (long) expiration); - - MAKE_STD_ZVAL(zcas); - ZVAL_DOUBLE(zcas, (double) cas); + ZVAL_STRINGL(&zkey, key, key_len); + ZVAL_STRINGL(&zdata, ((char *) data), (int) data_len); + ZVAL_LONG(&zflags, (long) flags); + ZVAL_LONG(&zexpiration, (long) expiration); + ZVAL_DOUBLE(&zcas, (double) cas); + ZVAL_NULL(&zresult_cas); - MAKE_STD_ZVAL(zresult_cas); - ZVAL_NULL(zresult_cas); + ZVAL_COPY(¶ms[0], &zcookie); + ZVAL_COPY(¶ms[1], &zkey); + ZVAL_COPY(¶ms[2], &zdata); + ZVAL_COPY(¶ms[3], &zflags); + ZVAL_COPY(¶ms[4], &zexpiration); + ZVAL_COPY(¶ms[5], &zcas); + ZVAL_COPY(¶ms[6], &zresult_cas); - params [0] = &zcookie; - params [1] = &zkey; - params [2] = &zdata; - params [3] = &zflags; - params [4] = &zexpiration; - params [5] = &zcas; - params [6] = &zresult_cas; - - retval = s_invoke_php_callback (&MEMC_GET_CB(event), params, 7 TSRMLS_CC); + retval = s_invoke_php_callback (&MEMC_GET_CB(event), params, 7); MEMC_MAKE_RESULT_CAS(zresult_cas, *result_cas); + zval_ptr_dtor(¶ms[0]); + zval_ptr_dtor(¶ms[1]); + zval_ptr_dtor(¶ms[2]); + zval_ptr_dtor(¶ms[3]); + zval_ptr_dtor(¶ms[4]); + zval_ptr_dtor(¶ms[5]); + zval_ptr_dtor(¶ms[6]); zval_ptr_dtor (&zcookie); zval_ptr_dtor (&zkey); zval_ptr_dtor (&zdata); @@ -535,11 +504,9 @@ static protocol_binary_response_status s_stat_handler (const void *cookie, const void *key, uint16_t key_len, memcached_binary_protocol_stat_response_handler response_handler) { - zval **params [3]; + zval params[3]; protocol_binary_response_status retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; - zval *zcookie, *zkey, *zbody; - - TSRMLS_FETCH(); + zval zcookie, zkey, zbody; if (!MEMC_HAS_CB(MEMC_SERVER_ON_STAT)) { return retval; @@ -547,29 +514,30 @@ protocol_binary_response_status s_stat_handler (const void *cookie, const void * MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); - MAKE_STD_ZVAL(zkey); - ZVAL_STRINGL(zkey, key, key_len, 1); + ZVAL_STRINGL(&zkey, key, key_len); + ZVAL_NULL(&zbody); - MAKE_STD_ZVAL(zbody); - ZVAL_NULL(zbody); + ZVAL_COPY(¶ms[0], &zcookie); + ZVAL_COPY(¶ms[1], &zkey); + ZVAL_COPY(¶ms[2], &zbody); - params [0] = &zcookie; - params [1] = &zkey; - params [2] = &zbody; - - retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_STAT), params, 3 TSRMLS_CC); + retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_STAT), params, 3); if (retval == PROTOCOL_BINARY_RESPONSE_SUCCESS) { - if (Z_TYPE_P (zbody) == IS_NULL) { + if (Z_TYPE(zbody) == IS_NULL) { retval = response_handler(cookie, NULL, 0, NULL, 0); } else { - if (Z_TYPE_P (zbody) != IS_STRING) { - convert_to_string (zbody); + if (Z_TYPE(zbody) != IS_STRING) { + convert_to_string(&zbody); } - retval = response_handler(cookie, key, key_len, Z_STRVAL_P (zbody), (uint32_t) Z_STRLEN_P (zbody)); + retval = response_handler(cookie, key, key_len, Z_STRVAL(zbody), (uint32_t) Z_STRLEN(zbody)); } } + + zval_ptr_dtor(¶ms[0]); + zval_ptr_dtor(¶ms[1]); + zval_ptr_dtor(¶ms[2]); zval_ptr_dtor (&zcookie); zval_ptr_dtor (&zkey); zval_ptr_dtor (&zbody); @@ -580,11 +548,9 @@ static protocol_binary_response_status s_version_handler (const void *cookie, memcached_binary_protocol_version_response_handler response_handler) { - zval **params [2]; + zval params[2]; protocol_binary_response_status retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; - zval *zcookie, *zversion; - - TSRMLS_FETCH(); + zval zcookie, zversion; if (!MEMC_HAS_CB(MEMC_SERVER_ON_VERSION)) { return retval; @@ -592,21 +558,23 @@ protocol_binary_response_status s_version_handler (const void *cookie, MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); - MAKE_STD_ZVAL(zversion); - ZVAL_NULL(zversion); + ZVAL_NULL(&zversion); - params [0] = &zcookie; - params [1] = &zversion; + ZVAL_COPY(¶ms[0], &zcookie); + ZVAL_COPY(¶ms[1], &zversion); - retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_VERSION), params, 2 TSRMLS_CC); + retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_VERSION), params, 2); if (retval == PROTOCOL_BINARY_RESPONSE_SUCCESS) { - if (Z_TYPE_P (zversion) != IS_STRING) { - convert_to_string (zversion); + if (Z_TYPE(zversion) != IS_STRING) { + convert_to_string(&zversion); } retval = response_handler (cookie, Z_STRVAL_P(zversion), (uint32_t) Z_STRLEN_P(zversion)); } + + zval_ptr_dtor(¶ms[0]); + zval_ptr_dtor(¶ms[1]); zval_ptr_dtor (&zcookie); zval_ptr_dtor (&zversion); return retval; @@ -623,36 +591,33 @@ void s_handle_memcached_event (evutil_socket_t fd, short what, void *arg) php_memc_client_t *client = (php_memc_client_t *) arg; memcached_protocol_event_t events; - TSRMLS_FETCH(); - if (!client->on_connect_invoked) { if (MEMC_HAS_CB(MEMC_SERVER_ON_CONNECT)) { - zval *zremoteip, *zremoteport; - zval **params [2]; + zval zremoteip, zremoteport; + zval params[2]; protocol_binary_response_status retval; struct sockaddr_in addr_in; socklen_t addr_in_len = sizeof(addr_in); - MAKE_STD_ZVAL(zremoteip); - MAKE_STD_ZVAL(zremoteport); - if (getpeername (fd, (struct sockaddr *) &addr_in, &addr_in_len) == 0) { - ZVAL_STRING(zremoteip, inet_ntoa (addr_in.sin_addr), 1); - ZVAL_LONG(zremoteport, ntohs (addr_in.sin_port)); + ZVAL_STRING(&zremoteip, inet_ntoa (addr_in.sin_addr), 1); + ZVAL_LONG(&zremoteport, ntohs (addr_in.sin_port)); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "getpeername failed: %s", strerror (errno)); - ZVAL_NULL(zremoteip); - ZVAL_NULL(zremoteport); + php_error_docref(NULL, E_WARNING, "getpeername failed: %s", strerror (errno)); + ZVAL_NULL(&zremoteip); + ZVAL_NULL(&zremoteport); } - params [0] = &zremoteip; - params [1] = &zremoteport; + ZVAL_COPY(¶ms[0], &zremoteip); + ZVAL_COPY(¶ms[1], &zremoteport); - retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_CONNECT), params, 2 TSRMLS_CC); + retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_CONNECT), params, 2); - zval_ptr_dtor (&zremoteip); - zval_ptr_dtor (&zremoteport); + zval_ptr_dtor(¶ms[0]); + zval_ptr_dtor(¶ms[1]); + zval_ptr_dtor(&zremoteip); + zval_ptr_dtor(&zremoteport); if (retval != PROTOCOL_BINARY_RESPONSE_SUCCESS) { memcached_protocol_client_destroy (client->protocol_client); @@ -683,7 +648,7 @@ void s_handle_memcached_event (evutil_socket_t fd, short what, void *arg) rc = event_base_once (client->event_base, fd, flags, s_handle_memcached_event, client, NULL); if (rc != 0) { - php_error_docref (NULL TSRMLS_CC, E_WARNING, "Failed to schedule events"); + php_error_docref (NULL, E_WARNING, "Failed to schedule events"); } } @@ -698,14 +663,12 @@ void s_accept_cb (evutil_socket_t fd, short what, void *arg) php_memc_proto_handler_t *handler = (php_memc_proto_handler_t *) arg; - TSRMLS_FETCH(); - /* Accept the connection */ addr_len = sizeof (addr); sock = accept (fd, (struct sockaddr *) &addr, &addr_len); if (sock == -1) { - php_error_docref (NULL TSRMLS_CC, E_WARNING, "Failed to accept the client: %s", strerror (errno)); + php_error_docref (NULL, E_WARNING, "Failed to accept the client: %s", strerror (errno)); return; } @@ -715,7 +678,7 @@ void s_accept_cb (evutil_socket_t fd, short what, void *arg) client->on_connect_invoked = 0; if (!client->protocol_client) { - php_error_docref (NULL TSRMLS_CC, E_WARNING, "Failed to allocate protocol client"); + php_error_docref (NULL, E_WARNING, "Failed to allocate protocol client"); efree (client); evutil_closesocket (sock); return; @@ -725,7 +688,7 @@ void s_accept_cb (evutil_socket_t fd, short what, void *arg) rc = event_base_once (handler->event_base, sock, EV_READ, s_handle_memcached_event, client, NULL); if (rc != 0) { - php_error_docref (NULL TSRMLS_CC, E_WARNING, "Failed to add event for client"); + php_error_docref (NULL, E_WARNING, "Failed to add event for client"); memcached_protocol_client_destroy (client->protocol_client); efree (client); evutil_closesocket (sock); @@ -771,59 +734,55 @@ evutil_socket_t s_create_listening_socket (const char *spec) int rc; - TSRMLS_FETCH(); - addr_len = sizeof (struct sockaddr); rc = evutil_parse_sockaddr_port (spec, (struct sockaddr *) &addr, &addr_len); if (rc != 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse bind address"); + php_error_docref(NULL, E_WARNING, "Failed to parse bind address"); return -1; } sock = socket (AF_INET, SOCK_STREAM, 0); if (sock < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "socket failed: %s", strerror (errno)); + php_error_docref(NULL, E_WARNING, "socket failed: %s", strerror (errno)); return -1; } rc = bind (sock, (struct sockaddr *) &addr, addr_len); if (rc < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "bind failed: %s", strerror (errno)); + php_error_docref(NULL, E_WARNING, "bind failed: %s", strerror (errno)); return -1; } rc = listen (sock, 1024); if (rc < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "listen failed: %s", strerror (errno)); + php_error_docref(NULL, E_WARNING, "listen failed: %s", strerror (errno)); return -1; } rc = evutil_make_socket_nonblocking (sock); if (rc != 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to make socket non-blocking: %s", strerror (errno)); + php_error_docref(NULL, E_WARNING, "failed to make socket non-blocking: %s", strerror (errno)); return -1; } rc = evutil_make_listen_socket_reuseable (sock); if (rc != 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to make socket reuseable: %s", strerror (errno)); + php_error_docref(NULL, E_WARNING, "failed to make socket reuseable: %s", strerror (errno)); return -1; } rc = evutil_make_socket_closeonexec (sock); if (rc != 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to make socket closeonexec: %s", strerror (errno)); + php_error_docref(NULL, E_WARNING, "failed to make socket closeonexec: %s", strerror (errno)); return -1; } return sock; } -zend_bool php_memc_proto_handler_run (php_memc_proto_handler_t *handler, const char *address) +zend_bool php_memc_proto_handler_run (php_memc_proto_handler_t *handler, zend_string *address) { struct event *accept_event; - evutil_socket_t sock = s_create_listening_socket (address); - - TSRMLS_FETCH(); + evutil_socket_t sock = s_create_listening_socket (address->val); if (sock == -1) { return 0; @@ -831,22 +790,22 @@ zend_bool php_memc_proto_handler_run (php_memc_proto_handler_t *handler, const c handler->event_base = event_base_new(); if (!handler->event_base) { - php_error_docref(NULL TSRMLS_CC, E_ERROR, "failed to allocate memory: %s", strerror (errno)); + php_error_docref(NULL, E_ERROR, "failed to allocate memory: %s", strerror (errno)); } accept_event = event_new (handler->event_base, sock, EV_READ | EV_PERSIST, s_accept_cb, handler); if (!accept_event) { - php_error_docref(NULL TSRMLS_CC, E_ERROR, "failed to allocate memory: %s", strerror (errno)); + php_error_docref(NULL, E_ERROR, "failed to allocate memory: %s", strerror (errno)); } event_add (accept_event, NULL); switch (event_base_dispatch (handler->event_base)) { case -1: - php_error_docref(NULL TSRMLS_CC, E_ERROR, "event_base_dispatch() failed: %s", strerror (errno)); + php_error_docref(NULL, E_ERROR, "event_base_dispatch() failed: %s", strerror (errno)); return 0; break; case 1: - php_error_docref(NULL TSRMLS_CC, E_ERROR, "no events registered"); + php_error_docref(NULL, E_ERROR, "no events registered"); return 0; break; @@ -865,4 +824,11 @@ void php_memc_proto_handler_destroy (php_memc_proto_handler_t **ptr) efree (handler); *ptr = NULL; -} \ No newline at end of file +} +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim: noet sw=4 ts=4 fdm=marker: + */ diff --git a/php_memcached_server.h b/php_memcached_server.h index 31676c53..285c608d 100644 --- a/php_memcached_server.h +++ b/php_memcached_server.h @@ -33,8 +33,8 @@ php_memc_proto_handler_t *php_memc_proto_handler_new (); void php_memc_proto_handler_destroy (php_memc_proto_handler_t **ptr); -zend_bool php_memc_proto_handler_run (php_memc_proto_handler_t *h, const char *address); +zend_bool php_memc_proto_handler_run (php_memc_proto_handler_t *h, zend_string *address); #endif -#endif \ No newline at end of file +#endif diff --git a/php_memcached_session.c b/php_memcached_session.c index a3ef5678..118805aa 100644 --- a/php_memcached_session.c +++ b/php_memcached_session.c @@ -27,7 +27,7 @@ ps_module ps_mod_memcached = { PS_MOD(memcached) }; -static int php_memc_sess_lock(memcached_st *memc, const char *key TSRMLS_DC) +static int php_memc_sess_lock(memcached_st *memc, const char *key) { char *lock_key = NULL; int lock_key_len = 0; @@ -72,7 +72,7 @@ static int php_memc_sess_lock(memcached_st *memc, const char *key TSRMLS_DC) write_retry_attempts--; continue; } - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Write of lock failed"); + php_error_docref(NULL, E_WARNING, "Write of lock failed"); break; } @@ -85,7 +85,7 @@ static int php_memc_sess_lock(memcached_st *memc, const char *key TSRMLS_DC) return -1; } -static void php_memc_sess_unlock(memcached_st *memc TSRMLS_DC) +static void php_memc_sess_unlock(memcached_st *memc) { if (MEMC_G(sess_locked)) { memcached_delete(memc, MEMC_G(sess_lock_key), MEMC_G(sess_lock_key_len), 0); @@ -103,13 +103,14 @@ PS_OPEN_FUNC(memcached) int plist_key_len = 0; if (!strncmp((char *)save_path, "PERSISTENT=", sizeof("PERSISTENT=") - 1)) { - zend_rsrc_list_entry *le = NULL; + zend_resource *le = NULL; + zval *le_z = NULL; char *e; p = (char *)save_path + sizeof("PERSISTENT=") - 1; if (!*p) { error: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid persistent id for session storage"); + php_error_docref(NULL, E_WARNING, "Invalid persistent id for session storage"); return FAILURE; } if ((e = strchr(p, ' '))) { @@ -118,7 +119,9 @@ PS_OPEN_FUNC(memcached) goto error; } plist_key_len++; - if (zend_hash_find(&EG(persistent_list), plist_key, plist_key_len, (void *)&le) == SUCCESS) { + + if ((le_z = zend_hash_str_find(&EG(persistent_list), plist_key, plist_key_len)) != NULL) { + le = Z_RES_P(le_z); if (le->type == php_memc_sess_list_entry()) { memc_sess = (memcached_sess *) le->ptr; PS_SET_MOD_DATA(memc_sess); @@ -146,7 +149,7 @@ PS_OPEN_FUNC(memcached) efree(plist_key); } memcached_free(memc_sess->memc_sess); - php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to enable memcached consistent hashing"); + php_error_docref(NULL, E_WARNING, "failed to enable memcached consistent hashing"); return FAILURE; } } @@ -160,7 +163,7 @@ PS_OPEN_FUNC(memcached) efree(plist_key); } memcached_free(memc_sess->memc_sess); - php_error_docref(NULL TSRMLS_CC, E_WARNING, "bad memcached key prefix in memcached.sess_prefix"); + php_error_docref(NULL, E_WARNING, "bad memcached key prefix in memcached.sess_prefix"); return FAILURE; } @@ -169,10 +172,10 @@ PS_OPEN_FUNC(memcached) } } else { memcached_server_list_free(servers); - php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not allocate libmemcached structure"); + php_error_docref(NULL, E_WARNING, "could not allocate libmemcached structure"); } } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to parse session.save_path"); + php_error_docref(NULL, E_WARNING, "failed to parse session.save_path"); } } else { memc_sess->memc_sess = php_memc_create_str(p, strlen(p)); @@ -180,12 +183,12 @@ PS_OPEN_FUNC(memcached) #ifdef HAVE_LIBMEMCACHED_CHECK_CONFIGURATION char error_buffer[1024]; if (libmemcached_check_configuration(p, strlen(p), error_buffer, sizeof(error_buffer)) != MEMCACHED_SUCCESS) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "session.save_path configuration error %s", error_buffer); + php_error_docref(NULL, E_WARNING, "session.save_path configuration error %s", error_buffer); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to initialize memcached session storage"); + php_error_docref(NULL, E_WARNING, "failed to initialize memcached session storage"); } #else - php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to initialize memcached session storage"); + php_error_docref(NULL, E_WARNING, "failed to initialize memcached session storage"); #endif } else { @@ -193,21 +196,25 @@ PS_OPEN_FUNC(memcached) PS_SET_MOD_DATA(memc_sess); if (plist_key) { - zend_rsrc_list_entry le; + zend_resource le; + zend_string *tmp_key; le.type = php_memc_sess_list_entry(); le.ptr = memc_sess; - if (zend_hash_update(&EG(persistent_list), (char *)plist_key, plist_key_len, (void *)&le, sizeof(le), NULL) == FAILURE) { + tmp_key = zend_string_init(plist_key, plist_key_len, 0); + if (zend_hash_update_mem(&EG(persistent_list), tmp_key, (void *)&le, sizeof(le)) == NULL) { + zend_string_release(tmp_key); efree(plist_key); - php_error_docref(NULL TSRMLS_CC, E_ERROR, "could not register persistent entry"); + php_error_docref(NULL, E_ERROR, "could not register persistent entry"); } + zend_string_release(tmp_key); efree(plist_key); } if (MEMC_G(sess_binary_enabled)) { if (memcached_behavior_set(memc_sess->memc_sess, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, (uint64_t) 1) == MEMCACHED_FAILURE) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to set memcached session binary protocol"); + php_error_docref(NULL, E_WARNING, "failed to set memcached session binary protocol"); return FAILURE; } } @@ -220,11 +227,11 @@ PS_OPEN_FUNC(memcached) if (MEMC_G(sess_sasl_username) && MEMC_G(sess_sasl_password)) { /* Force binary protocol */ if (memcached_behavior_set(memc_sess->memc_sess, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, (uint64_t) 1) == MEMCACHED_FAILURE) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to set memcached session binary protocol"); + php_error_docref(NULL, E_WARNING, "failed to set memcached session binary protocol"); return FAILURE; } if (memcached_set_sasl_auth_data(memc_sess->memc_sess, MEMC_G(sess_sasl_username), MEMC_G(sess_sasl_password)) == MEMCACHED_FAILURE) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to set memcached session sasl credentials"); + php_error_docref(NULL, E_WARNING, "failed to set memcached session sasl credentials"); return FAILURE; } MEMC_G(sess_sasl_data) = 1; @@ -235,23 +242,23 @@ PS_OPEN_FUNC(memcached) #endif if (MEMC_G(sess_number_of_replicas) > 0) { if (memcached_behavior_set(memc_sess->memc_sess, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, (uint64_t) MEMC_G(sess_number_of_replicas)) == MEMCACHED_FAILURE) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to set memcached session number of replicas"); + php_error_docref(NULL, E_WARNING, "failed to set memcached session number of replicas"); return FAILURE; } if (memcached_behavior_set(memc_sess->memc_sess, MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ, (uint64_t) MEMC_G(sess_randomize_replica_read)) == MEMCACHED_FAILURE) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to set memcached session randomize replica read"); + php_error_docref(NULL, E_WARNING, "failed to set memcached session randomize replica read"); } } if (memcached_behavior_set(memc_sess->memc_sess, MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT, (uint64_t) MEMC_G(sess_connect_timeout)) == MEMCACHED_FAILURE) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to set memcached connection timeout"); + php_error_docref(NULL, E_WARNING, "failed to set memcached connection timeout"); return FAILURE; } #ifdef HAVE_MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS /* Allow libmemcached remove failed servers */ if (MEMC_G(sess_remove_failed_enabled)) { if (memcached_behavior_set(memc_sess->memc_sess, MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS, (uint64_t) 1) == MEMCACHED_FAILURE) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to set: remove failed servers"); + php_error_docref(NULL, E_WARNING, "failed to set: remove failed servers"); return FAILURE; } } @@ -272,7 +279,7 @@ PS_CLOSE_FUNC(memcached) memcached_sess *memc_sess = PS_GET_MOD_DATA(); if (MEMC_G(sess_locking_enabled)) { - php_memc_sess_unlock(memc_sess->memc_sess TSRMLS_CC); + php_memc_sess_unlock(memc_sess->memc_sess); } if (memc_sess->memc_sess) { if (!memc_sess->is_persistent) { @@ -294,7 +301,7 @@ PS_READ_FUNC(memcached) { char *payload = NULL; size_t payload_len = 0; - int key_len = strlen(key); + int key_len = key->len; uint32_t flags = 0; memcached_return status; memcached_sess *memc_sess = PS_GET_MOD_DATA(); @@ -302,23 +309,22 @@ PS_READ_FUNC(memcached) key_length = strlen(MEMC_G(sess_prefix)) + key_len + 5; // prefix + "lock." if (!key_length || key_length >= MEMCACHED_MAX_KEY) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "The session id is too long or contains illegal characters"); + php_error_docref(NULL, E_WARNING, "The session id is too long or contains illegal characters"); PS(invalid_session_id) = 1; return FAILURE; } if (MEMC_G(sess_locking_enabled)) { - if (php_memc_sess_lock(memc_sess->memc_sess, key TSRMLS_CC) < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to clear session lock record"); + if (php_memc_sess_lock(memc_sess->memc_sess, key->val) < 0) { + php_error_docref(NULL, E_WARNING, "Unable to clear session lock record"); return FAILURE; } } - payload = memcached_get(memc_sess->memc_sess, key, key_len, &payload_len, &flags, &status); + payload = memcached_get(memc_sess->memc_sess, key->val, key_len, &payload_len, &flags, &status); if (status == MEMCACHED_SUCCESS) { - *val = estrndup(payload, payload_len); - *vallen = payload_len; + *val = zend_string_init(payload, payload_len, 1); free(payload); return SUCCESS; } else { @@ -328,7 +334,7 @@ PS_READ_FUNC(memcached) PS_WRITE_FUNC(memcached) { - int key_len = strlen(key); + int key_len = key->len; time_t expiration = 0; long write_try_attempts = 1; memcached_return status; @@ -337,7 +343,7 @@ PS_WRITE_FUNC(memcached) key_length = strlen(MEMC_G(sess_prefix)) + key_len + 5; // prefix + "lock." if (!key_length || key_length >= MEMCACHED_MAX_KEY) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "The session id is too long or contains illegal characters"); + php_error_docref(NULL, E_WARNING, "The session id is too long or contains illegal characters"); PS(invalid_session_id) = 1; return FAILURE; } @@ -352,7 +358,7 @@ PS_WRITE_FUNC(memcached) } do { - status = memcached_set(memc_sess->memc_sess, key, key_len, val, vallen, expiration, 0); + status = memcached_set(memc_sess->memc_sess, key->val, key_len, val->val, val->len, expiration, 0); if (status == MEMCACHED_SUCCESS) { return SUCCESS; } else { @@ -367,9 +373,9 @@ PS_DESTROY_FUNC(memcached) { memcached_sess *memc_sess = PS_GET_MOD_DATA(); - memcached_delete(memc_sess->memc_sess, key, strlen(key), 0); + memcached_delete(memc_sess->memc_sess, key->val, key->len, 0); if (MEMC_G(sess_locking_enabled)) { - php_memc_sess_unlock(memc_sess->memc_sess TSRMLS_CC); + php_memc_sess_unlock(memc_sess->memc_sess); } return SUCCESS; From 399b86bdcdd67039d271da9bbbe46cebe1749ffe Mon Sep 17 00:00:00 2001 From: Rasmus Lerdorf Date: Tue, 3 Feb 2015 12:35:55 -0800 Subject: [PATCH 002/104] More tests pass now --- php_memcached.c | 54 ++++++++++++++++++++++++++--------------- php_memcached_session.c | 2 -- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index 33570992..58fb66d4 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -536,7 +536,7 @@ PHP_METHOD(Memcached, getByKey) static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { zend_string *key; - zend_string *server_key; + zend_string *server_key = NULL; const char *payload = NULL; size_t payload_len = 0; uint32_t flags = 0; @@ -584,8 +584,11 @@ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1); } - status = memcached_mget_by_key(m_obj->memc, server_key->val, server_key->len, keys, key_lens, 1); - + if (by_key) { + status = memcached_mget_by_key(m_obj->memc, server_key->val, server_key->len, keys, key_lens, 1); + } else { + status = memcached_mget(m_obj->memc, keys, key_lens, 1); + } if (cas_token && Z_IS_REF(cas_token) && orig_cas_flag == 0) { memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, orig_cas_flag); } @@ -685,7 +688,7 @@ PHP_METHOD(Memcached, getMultiByKey) static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { zval *keys = NULL; - zend_string *server_key; + zend_string *server_key = NULL; size_t num_keys = 0; zval *entry = NULL; const char *payload = NULL; @@ -764,7 +767,11 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke } } - status = memcached_mget_by_key(m_obj->memc, server_key->val, server_key->len, mkeys, mkeys_len, i); + if (by_key) { + status = memcached_mget_by_key(m_obj->memc, server_key->val, server_key->len, mkeys, mkeys_len, i); + } else { + status = memcached_mget(m_obj->memc, mkeys, mkeys_len, i); + } /* Handle error, but ignore, there might still be some result */ php_memc_handle_error(i_obj, status); @@ -898,7 +905,7 @@ PHP_METHOD(Memcached, getDelayedByKey) static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { zval *keys = NULL; - zend_string *server_key; + zend_string *server_key = NULL; zend_bool with_cas = 0; size_t num_keys = 0; zval *entry = NULL; @@ -967,8 +974,11 @@ static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ /* * Issue the request, but collect results only if the result callback is provided. */ - status = memcached_mget_by_key(m_obj->memc, server_key->val, server_key->len, mkeys, mkeys_len, i); - + if (by_key) { + status = memcached_mget_by_key(m_obj->memc, server_key->val, server_key->len, mkeys, mkeys_len, i); + } else { + status = memcached_mget(m_obj->memc, mkeys, mkeys_len, i); + } /* * Restore the CAS support flag, but only if we had to turn it on. */ @@ -1213,7 +1223,7 @@ PHP_METHOD(Memcached, setMultiByKey) static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { zval *entries; - zend_string *server_key; + zend_string *server_key = NULL; time_t expiration = 0; long udf_flags = 0; zval *entry; @@ -1373,7 +1383,7 @@ PHP_METHOD(Memcached, replaceByKey) static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool by_key) { zend_string *key; - zend_string *server_key; + zend_string *server_key = NULL; zend_string *s_value; zval s_zvalue; zval *value; @@ -1468,7 +1478,7 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool retry: switch (op) { case MEMC_OP_SET: - if (!server_key->val) { + if (!server_key) { status = memcached_set(m_obj->memc, key->val, key->len, payload, payload_len, expiration, flags); } else { status = memcached_set_by_key(m_obj->memc, server_key->val, server_key->len, key->val, @@ -1477,7 +1487,7 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool break; #ifdef HAVE_MEMCACHED_TOUCH case MEMC_OP_TOUCH: - if (!server_key->val) { + if (!server_key) { status = memcached_touch(m_obj->memc, key->val, key->len, expiration); } else { status = memcached_touch_by_key(m_obj->memc, server_key->val, server_key->len, key->val, @@ -1486,7 +1496,7 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool break; #endif case MEMC_OP_ADD: - if (!server_key->val) { + if (!server_key) { status = memcached_add(m_obj->memc, key->val, key->len, payload, payload_len, expiration, flags); } else { status = memcached_add_by_key(m_obj->memc, server_key->val, server_key->len, key->val, @@ -1495,7 +1505,7 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool break; case MEMC_OP_REPLACE: - if (!server_key->val) { + if (!server_key) { status = memcached_replace(m_obj->memc, key->val, key->len, payload, payload_len, expiration, flags); } else { status = memcached_replace_by_key(m_obj->memc, server_key->val, server_key->len, key->val, @@ -1504,7 +1514,7 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool break; case MEMC_OP_APPEND: - if (!server_key->val) { + if (!server_key) { status = memcached_append(m_obj->memc, key->val, key->len, payload, payload_len, expiration, flags); } else { status = memcached_append_by_key(m_obj->memc, server_key->val, server_key->len, key->val, @@ -1513,7 +1523,7 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool break; case MEMC_OP_PREPEND: - if (!server_key->val) { + if (!server_key) { status = memcached_prepend(m_obj->memc, key->val, key->len, payload, payload_len, expiration, flags); } else { status = memcached_prepend_by_key(m_obj->memc, server_key->val, server_key->len, key->val, @@ -1547,7 +1557,7 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) double cas_d; uint64_t cas; zend_string *key; - zend_string *server_key; + zend_string *server_key = NULL; zval *value; time_t expiration = 0; long udf_flags = 0; @@ -1689,8 +1699,12 @@ static void php_memc_delete_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) RETURN_FALSE; } - status = memcached_delete_by_key(m_obj->memc, server_key->val, server_key->len, key->val, + if (by_key) { + status = memcached_delete_by_key(m_obj->memc, server_key->val, server_key->len, key->val, key->len, expiration); + } else { + status = memcached_delete(m_obj->memc, key->val, key->len, expiration); + } if (php_memc_handle_error(i_obj, status) < 0) { RETURN_FALSE; @@ -1704,7 +1718,7 @@ static void php_memc_delete_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) static void php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { zval *entries; - zend_string *server_key; + zend_string *server_key = NULL; time_t expiration = 0; zval *entry; @@ -1755,7 +1769,7 @@ static void php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by /* {{{ -- php_memc_incdec_impl */ static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key, zend_bool incr) { - zend_string *key, *server_key; + zend_string *key, *server_key = NULL; long offset = 1; uint64_t value, initial = 0; time_t expiry = 0; diff --git a/php_memcached_session.c b/php_memcached_session.c index 118805aa..1d2dbe32 100644 --- a/php_memcached_session.c +++ b/php_memcached_session.c @@ -310,7 +310,6 @@ PS_READ_FUNC(memcached) key_length = strlen(MEMC_G(sess_prefix)) + key_len + 5; // prefix + "lock." if (!key_length || key_length >= MEMCACHED_MAX_KEY) { php_error_docref(NULL, E_WARNING, "The session id is too long or contains illegal characters"); - PS(invalid_session_id) = 1; return FAILURE; } @@ -344,7 +343,6 @@ PS_WRITE_FUNC(memcached) key_length = strlen(MEMC_G(sess_prefix)) + key_len + 5; // prefix + "lock." if (!key_length || key_length >= MEMCACHED_MAX_KEY) { php_error_docref(NULL, E_WARNING, "The session id is too long or contains illegal characters"); - PS(invalid_session_id) = 1; return FAILURE; } From 479b6e2ef455e1a2679553a5538ba605f594363b Mon Sep 17 00:00:00 2001 From: Rasmus Lerdorf Date: Tue, 3 Feb 2015 12:57:34 -0800 Subject: [PATCH 003/104] Fix 4 more tests --- php_memcached.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index 58fb66d4..eda04625 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -580,7 +580,7 @@ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) /* * Enable CAS support, but only if it is currently disabled. */ - if (cas_token && Z_IS_REF(cas_token) && orig_cas_flag == 0) { + if (cas_token && Z_ISREF_P(cas_token) && orig_cas_flag == 0) { memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1); } @@ -589,7 +589,7 @@ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) } else { status = memcached_mget(m_obj->memc, keys, key_lens, 1); } - if (cas_token && Z_IS_REF(cas_token) && orig_cas_flag == 0) { + if (cas_token && Z_ISREF_P(cas_token) && orig_cas_flag == 0) { memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, orig_cas_flag); } @@ -760,7 +760,7 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke /* * Enable CAS support, but only if it is currently disabled. */ - if (cas_tokens && Z_IS_REF(cas_tokens)) { + if (cas_tokens && Z_ISREF_P(cas_tokens)) { orig_cas_flag = memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS); if (orig_cas_flag == 0) { memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1); @@ -778,7 +778,7 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke /* * Restore the CAS support flag, but only if we had to turn it on. */ - if (cas_tokens && Z_IS_REF(cas_tokens) && orig_cas_flag == 0) { + if (cas_tokens && Z_ISREF_P(cas_tokens) && orig_cas_flag == 0) { memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, orig_cas_flag); } @@ -790,7 +790,7 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke * returned as doubles, because we cannot store potential 64-bit values in longs. */ if (cas_tokens) { - if (Z_IS_REF(cas_tokens)) { + if (Z_ISREF_P(cas_tokens)) { /* cas_tokens was passed by reference, we'll create an array for it. */ ZVAL_DEREF(cas_tokens); SEPARATE_ZVAL(cas_tokens); From 3a93af390d0430dcae00b860b65e8ec5eddf82e9 Mon Sep 17 00:00:00 2001 From: Rasmus Lerdorf Date: Tue, 3 Feb 2015 13:32:52 -0800 Subject: [PATCH 004/104] minor cleanup --- php_memcached.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index eda04625..9e381584 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -2861,12 +2861,8 @@ zend_object_value php_memc_server_new(zend_class_entry *ce) zval *tmp; intern = ecalloc(1, sizeof(php_memc_server_t)); - zend_object_std_init (&intern->zo, ce); -#if PHP_VERSION_ID >= 50400 - object_properties_init( (zend_object *) intern, ce); -#else - zend_hash_copy(intern->zo.properties, &ce->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); -#endif + zend_object_std_init(&intern->zo, ce); + object_properties_init(&intern->zo, ce); intern->handler = php_memc_proto_handler_new (); From a3279a8478483f750274bc1e74fe5d1a540aa354 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Wed, 4 Feb 2015 17:30:29 +0800 Subject: [PATCH 005/104] Various bug fixes --- php_libmemcached_compat.c | 3 +- php_memcached.c | 73 ++++++++++++++++++++++----------------- php_memcached.h | 1 + tests/version.phpt | 4 +-- 4 files changed, 47 insertions(+), 34 deletions(-) diff --git a/php_libmemcached_compat.c b/php_libmemcached_compat.c index f238709e..f49b162b 100644 --- a/php_libmemcached_compat.c +++ b/php_libmemcached_compat.c @@ -49,4 +49,5 @@ memcached_st *php_memc_create_str (const char *str, size_t str_len) } return memc; #endif -} \ No newline at end of file +} + diff --git a/php_memcached.c b/php_memcached.c index 9e381584..500110af 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -366,7 +366,7 @@ static zend_bool php_memcached_on_new_callback(zval *object, zend_fcall_info *fc } /* Call the cb */ - ZVAL_COPY_VALUE(¶ms[0], object); + ZVAL_COPY(¶ms[0], object); fci->params = params; fci->param_count = 2; @@ -420,7 +420,7 @@ static PHP_METHOD(Memcached, __construct) is_persistent = 1; plist_key = zend_string_alloc(sizeof("memcached:id=") + persistent_id->len - 1, 0); - snprintf(plist_key->val, plist_key->len+1, "memcached:id=%s", persistent_id->val); + snprintf(plist_key->val, plist_key->len + 1, "memcached:id=%s", persistent_id->val); if ((le = zend_hash_find_ptr(&EG(persistent_list), plist_key)) != NULL) { if (le->type == php_memc_list_entry()) { m_obj = (struct memc_obj *) le->ptr; @@ -500,7 +500,8 @@ static PHP_METHOD(Memcached, __construct) le.type = php_memc_list_entry(); le.ptr = m_obj; GC_REFCOUNT(&le) = 1; - if (zend_hash_update_mem(&EG(persistent_list), plist_key, &le, sizeof(le)) == NULL) { + /* plist_key is not a persistent allocated key, thus we use str_update here */ + if (zend_hash_str_update_mem(&EG(persistent_list), plist_key->val, plist_key->len, &le, sizeof(le)) == NULL) { if (plist_key) { zend_string_release(plist_key); } @@ -853,13 +854,13 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke continue; } - add_assoc_zval_ex(return_value, res_key, res_key_len+1, &value); + add_assoc_zval_ex(return_value, res_key, res_key_len, &value); if (cas_tokens) { cas = memcached_result_cas(&result); - add_assoc_double_ex(cas_tokens, res_key, res_key_len+1, (double)cas); + add_assoc_double_ex(cas_tokens, res_key, res_key_len, (double)cas); } if (udf_flags) { - add_assoc_long_ex(udf_flags, res_key, res_key_len+1, MEMC_VAL_GET_USER_FLAGS(flags)); + add_assoc_long_ex(udf_flags, res_key, res_key_len, MEMC_VAL_GET_USER_FLAGS(flags)); } } @@ -946,7 +947,7 @@ static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ convert_to_string_ex(entry); } - if (Z_TYPE_PP(entry) == IS_STRING && Z_STRLEN_PP(entry) > 0) { + if (Z_TYPE_P(entry) == IS_STRING && Z_STRLEN_P(entry) > 0) { mkeys[i] = Z_STRVAL_P(entry); mkeys_len[i] = Z_STRLEN_P(entry); i++; @@ -1227,7 +1228,7 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke time_t expiration = 0; long udf_flags = 0; zval *entry; - zend_string *str_key = NULL; + zend_string *skey, *str_key = NULL; ulong num_key; char *payload; size_t payload_len; @@ -1262,9 +1263,9 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke } } - ZEND_HASH_FOREACH_KEY_VAL (Z_ARRVAL_P(entries), num_key, str_key, entry) { - if (str_key) { - str_key = zend_string_init(str_key->val, str_key->len, 0); + ZEND_HASH_FOREACH_KEY_VAL (Z_ARRVAL_P(entries), num_key, skey, entry) { + if (skey) { + str_key = skey; } else if (num_key || num_key == 0) { /* Array keys are unsigned, but php integers are signed. * Keys must be converted to signed strings that match @@ -1288,26 +1289,36 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke payload = php_memc_zval_to_payload(entry, &payload_len, &flags, m_obj->serializer, m_obj->compression_type); if (payload == NULL) { i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE; - zend_string_release(str_key); + if (!skey) { + zend_string_release(str_key); + } RETURN_FALSE; } retry: if (!by_key) { status = memcached_set(m_obj->memc, str_key->val, str_key->len, payload, payload_len, expiration, flags); - zend_string_release(str_key); + if (!skey) { + zend_string_release(str_key); + } } else { status = memcached_set_by_key(m_obj->memc, server_key->val, server_key->len, str_key->val, str_key->len, payload, payload_len, expiration, flags); - zend_string_release(str_key); + if (!skey) { + zend_string_release(str_key); + } } if (php_memc_handle_error(i_obj, status) < 0) { PHP_MEMC_FAILOVER_RETRY - zend_string_release(str_key); + if (!skey) { + zend_string_release(str_key); + } efree(payload); RETURN_FALSE; } - zend_string_release(str_key); + if (!skey) { + zend_string_release(str_key); + } efree(payload); } ZEND_HASH_FOREACH_END(); @@ -2334,7 +2345,7 @@ static PHP_METHOD(Memcached, getOption) result = memcached_callback_get(m_obj->memc, MEMCACHED_CALLBACK_PREFIX_KEY, &retval); if (retval == MEMCACHED_SUCCESS && result) { #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX == 0x00049000 - RETURN_STRINGL(result, strlen(result) - 1); + RETURN_STRINGL(result, strlen(result)); #else RETURN_STRING(result); #endif @@ -2831,7 +2842,6 @@ static void php_memc_free_storage(zend_object *obj) zend_object_std_dtor(&i_obj->zo); i_obj->obj = NULL; - efree(i_obj); } zend_object *php_memc_new(zend_class_entry *ce) @@ -2946,7 +2956,7 @@ static memcached_return php_memc_do_stats_callback(const memcached_st *ptr, php_ add_assoc_long(&entry, "bytes_written", context->stats[context->i].bytes_written); add_assoc_stringl(&entry, "version", context->stats[context->i].version, strlen(context->stats[context->i].version)); - add_assoc_zval_ex(context->return_value, hostport, hostport_len+1, &entry); + add_assoc_zval_ex(context->return_value, hostport, hostport_len, &entry); efree(hostport); /* Increment the server count in our context structure. Failure to do so will cause only the stats for the last server to get displayed. */ @@ -2974,7 +2984,7 @@ static memcached_return php_memc_do_version_callback(const memcached_st *ptr, ph instance->micro_version); #endif - add_assoc_stringl_ex(context->return_value, hostport, hostport_len+1, version, version_len); + add_assoc_stringl_ex(context->return_value, hostport, hostport_len, version, version_len); efree(hostport); return MEMCACHED_SUCCESS; } @@ -3206,7 +3216,7 @@ char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t *flags default: if (!s_serialize_value (serializer, value, &buf, flags)) { - smart_str_free (&buf); + smart_str_free(&buf); return NULL; } pl = buf.s->val; @@ -3388,12 +3398,7 @@ static int php_memc_zval_from_payload(zval *value, const char *payload_in, size_ switch (MEMC_VAL_GET_TYPE(flags)) { case MEMC_VAL_IS_STRING: - if (payload_emalloc) { - ZVAL_STRINGL(value, pl, payload_len); - payload_emalloc = 0; - } else { - ZVAL_STRINGL(value, pl, payload_len); - } + ZVAL_STRINGL(value, pl, payload_len); break; case MEMC_VAL_IS_LONG: @@ -3514,6 +3519,7 @@ static memcached_return php_memc_do_cache_callback(zval *zmemc_obj, zend_fcall_i zval params[4]; zval retval; zval z_key; + zval z_val; zval z_expiration; uint32_t flags = 0; @@ -3523,8 +3529,10 @@ static memcached_return php_memc_do_cache_callback(zval *zmemc_obj, zend_fcall_i int result; ZVAL_STR(&z_key, key); - ZVAL_NULL(value); - ZVAL_LONG(&z_expiration, 0); + ZVAL_NULL(&z_val); + ZVAL_NEW_REF(value, &z_val); + ZVAL_NEW_REF(&z_expiration, &z_val); + ZVAL_LONG(Z_REFVAL(z_expiration), 0); ZVAL_COPY(¶ms[0], zmemc_obj); ZVAL_COPY(¶ms[1], &z_key); @@ -3536,9 +3544,12 @@ static memcached_return php_memc_do_cache_callback(zval *zmemc_obj, zend_fcall_i fci->param_count = 4; result = zend_call_function(fci, fcc); + ZVAL_UNREF(value); + ZVAL_UNREF(&z_expiration); if (result == SUCCESS && Z_TYPE(retval) != IS_UNDEF) { - i_obj = (php_memc_t *) Z_OBJ_P(zmemc_obj); - struct memc_obj *m_obj = i_obj->obj; + struct memc_obj *m_obj; + i_obj = Z_MEMC_OBJ_P(zmemc_obj) + m_obj = i_obj->obj; if (zend_is_true(&retval)) { time_t expiration; diff --git a/php_memcached.h b/php_memcached.h index da4d6b92..2ce8e730 100644 --- a/php_memcached.h +++ b/php_memcached.h @@ -21,6 +21,7 @@ #include "php.h" #include "main/php_config.h" +#include "Zend/zend_smart_str.h" #ifdef HAVE_CONFIG_H # include "config.h" diff --git a/tests/version.phpt b/tests/version.phpt index f9adcc52..8ffe275a 100644 --- a/tests/version.phpt +++ b/tests/version.phpt @@ -13,6 +13,6 @@ echo "OK" . PHP_EOL; --EXPECTF-- array(1) { ["%s:%d"]=> - string(6) "%d.%d.%d" + string(%d) "%d.%d.%d" } -OK \ No newline at end of file +OK From 35a543f0cb7a9825b8b19ddcf2ff44435a208355 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Wed, 4 Feb 2015 17:48:36 +0800 Subject: [PATCH 006/104] Fixed memory leak --- php_memcached.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php_memcached.c b/php_memcached.c index 500110af..be745c26 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -1699,7 +1699,7 @@ static void php_memc_delete_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|l", &key, &expiration) == FAILURE) { return; } - server_key = zend_string_copy(key); + server_key = key; } MEMC_METHOD_FETCH_OBJECT; From cbcbece3619bd067d64094cc04f7d6a676a28b66 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Wed, 4 Feb 2015 17:54:26 +0800 Subject: [PATCH 007/104] Fixed getStat --- php_memcached.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php_memcached.c b/php_memcached.c index be745c26..6a9776ab 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -2927,7 +2927,7 @@ static memcached_return php_memc_do_stats_callback(const memcached_st *ptr, php_ int hostport_len; struct callbackContext* context = (struct callbackContext*) in_context; zval entry; - hostport_len = spprintf(&hostport, 0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance) - 1); + hostport_len = spprintf(&hostport, 0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance)); array_init(&entry); From 6851bdd95f2a0f776fc55b4be8a43e2993a1268e Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Wed, 4 Feb 2015 18:01:11 +0800 Subject: [PATCH 008/104] Fixed memory leak --- php_memcached.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index 6a9776ab..99eed2f1 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -2548,16 +2548,9 @@ uint32_t *s_zval_to_uint32_array (zval *input, size_t *num_elements) if (Z_TYPE_P(pzval) == IS_LONG) { value = Z_LVAL_P(pzval); - } - else { - zval *tmp_zval, *tmp_pzval; - tmp_zval = pzval; - zval_copy_ctor(tmp_zval); - tmp_pzval = tmp_zval; - convert_to_long(tmp_pzval); - - value = (Z_LVAL_P(tmp_pzval) > 0) ? Z_LVAL_P(tmp_pzval) : 0; - zval_dtor(tmp_pzval); + } else { + value = zval_get_long(pzval); + value = value > 0? value : 0; } if (value < 0) { From 229c6842225876c8f8bfca8706616db516451bc8 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Wed, 4 Feb 2015 18:34:34 +0800 Subject: [PATCH 009/104] Better implementation --- php_memcached.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index 99eed2f1..ef49c8ec 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -3513,7 +3513,7 @@ static memcached_return php_memc_do_cache_callback(zval *zmemc_obj, zend_fcall_i zval retval; zval z_key; zval z_val; - zval z_expiration; + zval *expiration, z_expiration; uint32_t flags = 0; memcached_return rc; @@ -3523,41 +3523,37 @@ static memcached_return php_memc_do_cache_callback(zval *zmemc_obj, zend_fcall_i ZVAL_STR(&z_key, key); ZVAL_NULL(&z_val); - ZVAL_NEW_REF(value, &z_val); - ZVAL_NEW_REF(&z_expiration, &z_val); + ZVAL_NEW_REF(&z_val, value); + ZVAL_NEW_REF(&z_expiration, value); ZVAL_LONG(Z_REFVAL(z_expiration), 0); ZVAL_COPY(¶ms[0], zmemc_obj); ZVAL_COPY(¶ms[1], &z_key); - ZVAL_COPY(¶ms[2], value); - ZVAL_COPY(¶ms[3], &z_expiration); + ZVAL_COPY_VALUE(¶ms[2], &z_val); + ZVAL_COPY_VALUE(¶ms[3], &z_expiration); fci->retval = &retval; fci->params = params; fci->param_count = 4; result = zend_call_function(fci, fcc); - ZVAL_UNREF(value); - ZVAL_UNREF(&z_expiration); + ZVAL_DUP(value, Z_REFVAL(z_val)); + expiration = Z_REFVAL(z_expiration); if (result == SUCCESS && Z_TYPE(retval) != IS_UNDEF) { struct memc_obj *m_obj; i_obj = Z_MEMC_OBJ_P(zmemc_obj) m_obj = i_obj->obj; if (zend_is_true(&retval)) { - time_t expiration; + time_t expir; - if (Z_TYPE(z_expiration) != IS_LONG) { - convert_to_long(&z_expiration); - } - - expiration = Z_LVAL(z_expiration); + expir = zval_get_long(expiration); payload = php_memc_zval_to_payload(value, &payload_len, &flags, m_obj->serializer, m_obj->compression_type); if (payload == NULL) { status = (memcached_return)MEMC_RES_PAYLOAD_FAILURE; } else { - rc = memcached_set(m_obj->memc, key->val, key->len, payload, payload_len, expiration, flags); + rc = memcached_set(m_obj->memc, key->val, key->len, payload, payload_len, expir, flags); if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED) { status = rc; } @@ -3571,8 +3567,6 @@ static memcached_return php_memc_do_cache_callback(zval *zmemc_obj, zend_fcall_i } else { if (result == FAILURE) { - zval_ptr_dtor(&z_key); - zval_ptr_dtor(&z_expiration); php_error_docref(NULL, E_WARNING, "could not invoke cache callback"); } status = MEMCACHED_FAILURE; @@ -3585,6 +3579,7 @@ static memcached_return php_memc_do_cache_callback(zval *zmemc_obj, zend_fcall_i } zval_ptr_dtor(&z_key); + zval_ptr_dtor(&z_val); zval_ptr_dtor(&z_expiration); return status; From 1b2c2251f954d785c6ef9e05a8153eba69b96573 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Wed, 4 Feb 2015 20:52:34 +0800 Subject: [PATCH 010/104] Fixed memleak, and use the recently added object_size api --- php_memcached.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index ef49c8ec..3a25a1a6 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -546,6 +546,7 @@ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) size_t key_lens[1] = { 0 }; zval *cas_token = NULL; zval *udf_flags = NULL; + uint64_t orig_cas_flag; zend_fcall_info fci = empty_fcall_info; zend_fcall_info_cache fcc = empty_fcall_info_cache; memcached_result_st result; @@ -575,7 +576,6 @@ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) keys[0] = key->val; key_lens[0] = key->len; - uint64_t orig_cas_flag; orig_cas_flag = memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS); /* @@ -612,6 +612,8 @@ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) * ourselves. */ if (cas_token) { + ZVAL_DEREF(cas_token); + zval_ptr_dtor(cas_token); ZVAL_DOUBLE(cas_token, 0.0); } @@ -653,8 +655,7 @@ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) if (cas_token) { ZVAL_DEREF(cas_token); - SEPARATE_ZVAL(cas_token); - zval_dtor(cas_token); + zval_ptr_dtor(cas_token); ZVAL_DOUBLE(cas_token, (double)cas); } @@ -2839,7 +2840,7 @@ static void php_memc_free_storage(zend_object *obj) zend_object *php_memc_new(zend_class_entry *ce) { - php_memc_t *i_obj = ecalloc(1, sizeof(php_memc_t) + sizeof(zval) * (ce->default_properties_count - 1)); + php_memc_t *i_obj = ecalloc(1, sizeof(php_memc_t) + zend_object_properties_size(ce)); zend_object_std_init(&i_obj->zo, ce); object_properties_init(&i_obj->zo, ce); From e4f8f395f979a80e52ed04b32e6ce62eb2c9b298 Mon Sep 17 00:00:00 2001 From: Rasmus Lerdorf Date: Wed, 4 Feb 2015 08:16:57 -0800 Subject: [PATCH 011/104] Down to 18 failed tests now --- php_memcached.h | 1 - 1 file changed, 1 deletion(-) diff --git a/php_memcached.h b/php_memcached.h index 2ce8e730..da4d6b92 100644 --- a/php_memcached.h +++ b/php_memcached.h @@ -21,7 +21,6 @@ #include "php.h" #include "main/php_config.h" -#include "Zend/zend_smart_str.h" #ifdef HAVE_CONFIG_H # include "config.h" From 1bb38ab0f7f58d2a7e91b90769e427a5066db4db Mon Sep 17 00:00:00 2001 From: Rasmus Lerdorf Date: Wed, 4 Feb 2015 09:37:06 -0800 Subject: [PATCH 012/104] Oops, need this for the inline stuff --- php_memcached.h | 1 + 1 file changed, 1 insertion(+) diff --git a/php_memcached.h b/php_memcached.h index da4d6b92..b96ef37a 100644 --- a/php_memcached.h +++ b/php_memcached.h @@ -20,6 +20,7 @@ #define PHP_MEMCACHED_H #include "php.h" +#include "Zend/zend_smart_str.h" #include "main/php_config.h" #ifdef HAVE_CONFIG_H From a9f703c3849a1056f356bdfc21ae1f3280fe2907 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Thu, 5 Feb 2015 11:15:51 +0800 Subject: [PATCH 013/104] Use strpprintf --- php_memcached.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index 3a25a1a6..a1ea6835 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -2760,11 +2760,9 @@ static PHP_METHOD(Memcached, getResultMessage) case MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE: case MEMCACHED_UNKNOWN_READ_FAILURE: if (i_obj->memc_errno) { - char *str; - int str_len; - str_len = spprintf(&str, 0, "%s: %s", memcached_strerror(m_obj->memc, (memcached_return)i_obj->rescode), - strerror(i_obj->memc_errno)); - RETURN_STRINGL(str, str_len); + zend_string *str = strpprintf(0, "%s: %s", + memcached_strerror(m_obj->memc, (memcached_return)i_obj->rescode), strerror(i_obj->memc_errno)); + RETURN_STR(str); } /* Fall through */ default: From 0021b5c08344b84cfe9504dc9b5cbfaac331942b Mon Sep 17 00:00:00 2001 From: Yasuo Ohgaki Date: Thu, 12 Feb 2015 13:28:52 +0900 Subject: [PATCH 014/104] Use new session save handler --- php_memcached_session.c | 62 +++++++++++++++++++++++++++++++++++++-- php_memcached_session.h | 5 +++- tests/session_basic2.phpt | 47 +++++++++++++++++++++++++++++ tests/session_basic3.phpt | 47 +++++++++++++++++++++++++++++ 4 files changed, 157 insertions(+), 4 deletions(-) create mode 100644 tests/session_basic2.phpt create mode 100644 tests/session_basic3.phpt diff --git a/php_memcached_session.c b/php_memcached_session.c index 1d2dbe32..4d1a2572 100644 --- a/php_memcached_session.c +++ b/php_memcached_session.c @@ -24,7 +24,7 @@ extern ZEND_DECLARE_MODULE_GLOBALS(php_memcached) #define MEMC_SESS_LOCK_EXPIRATION 30 ps_module ps_mod_memcached = { - PS_MOD(memcached) + PS_MOD_UPDATE_TIMESTAMP(memcached) }; static int php_memc_sess_lock(memcached_st *memc, const char *key) @@ -346,8 +346,8 @@ PS_WRITE_FUNC(memcached) return FAILURE; } - if (PS(gc_maxlifetime) > 0) { - expiration = PS(gc_maxlifetime); + if (maxlifetime > 0) { + expiration = maxlifetime; } /* Set the number of write retry attempts to the number of replicas times the number of attempts to remove a server plus the initial write */ @@ -383,4 +383,60 @@ PS_GC_FUNC(memcached) { return SUCCESS; } + +PS_CREATE_SID_FUNC(memcached) +{ + zend_string *sid; + int maxfail = 3; + memcached_sess *memc_sess = PS_GET_MOD_DATA(); + + do { + sid = php_session_create_id((void**)&memc_sess); + if (!sid) { + if (--maxfail < 0) { + return NULL; + } else { + continue; + } + } + /* Check collision */ + /* FIXME: mod_data(memc_sess) should not be NULL (User handler could be NULL) */ + if (memc_sess && memcached_exist(memc_sess->memc_sess, sid->val, sid->len) == MEMCACHED_SUCCESS) { + if (sid) { + zend_string_release(sid); + sid = NULL; + } + if (--maxfail < 0) { + return NULL; + } + } + } while(!sid); + + return sid; +} + +PS_VALIDATE_SID_FUNC(memcached) +{ + memcached_sess *memc_sess = PS_GET_MOD_DATA(); + + if (memcached_exist(memc_sess->memc_sess, key->val, key->len) == MEMCACHED_SUCCESS) { + return SUCCESS; + } else { + return FAILURE; + } +} + +PS_UPDATE_TIMESTAMP_FUNC(memcached) +{ + memcached_sess *memc_sess = PS_GET_MOD_DATA(); + time_t expiration = 0; + + if (maxlifetime > 0) { + expiration = maxlifetime; + } + if (memcached_touch(memc_sess->memc_sess, key->val, key->len, expiration) == MEMCACHED_FAILURE) { + return FAILURE; + } + return SUCCESS; +} /* }}} */ diff --git a/php_memcached_session.h b/php_memcached_session.h index 97fe2005..4118362f 100644 --- a/php_memcached_session.h +++ b/php_memcached_session.h @@ -24,7 +24,7 @@ extern ps_module ps_mod_memcached; #define ps_memcached_ptr &ps_mod_memcached -PS_FUNCS(memcached); +PS_FUNCS_UPDATE_TIMESTAMP(memcached); PS_OPEN_FUNC(memcached); PS_CLOSE_FUNC(memcached); @@ -32,5 +32,8 @@ PS_READ_FUNC(memcached); PS_WRITE_FUNC(memcached); PS_DESTROY_FUNC(memcached); PS_GC_FUNC(memcached); +PS_CREATE_SID_FUNC(memcached); +PS_VALIDATE_SID_FUNC(memcached); +PS_UPDATE_TIMESTAMP_FUNC(memcached); #endif /* PHP_MEMCACHED_SESSION_H */ diff --git a/tests/session_basic2.phpt b/tests/session_basic2.phpt new file mode 100644 index 00000000..f99063a8 --- /dev/null +++ b/tests/session_basic2.phpt @@ -0,0 +1,47 @@ +--TEST-- +Session basic open, write, destroy +--SKIPIF-- + +--INI-- +memcached.sess_locking = on +memcached.sess_lock_wait = 150000 +memcached.sess_prefix = "memc.sess.key." +session.save_handler = memcached + +--FILE-- +TRUE); +$_SESSION['foo'] = 1; +session_write_close(); + +$_SESSION = NULL; + +var_dump($_SESSION); +session_start(); +var_dump($_SESSION); +session_write_close(); + +session_start(); +session_destroy(); + +session_start(); +var_dump($_SESSION); +session_write_close(); + + +--EXPECT-- +NULL +array(1) { + ["foo"]=> + int(1) +} +array(0) { +} diff --git a/tests/session_basic3.phpt b/tests/session_basic3.phpt new file mode 100644 index 00000000..fc4e7ae7 --- /dev/null +++ b/tests/session_basic3.phpt @@ -0,0 +1,47 @@ +--TEST-- +Session basic open, write, destroy +--SKIPIF-- + +--INI-- +memcached.sess_locking = on +memcached.sess_lock_wait = 150000 +memcached.sess_prefix = "memc.sess.key." +session.save_handler = memcached + +--FILE-- +TRUE); +$_SESSION['foo'] = 1; +session_write_close(); + +$_SESSION = NULL; + +var_dump($_SESSION); +session_start(); +var_dump($_SESSION); +session_write_close(); + +session_start(); +session_destroy(); + +session_start(); +var_dump($_SESSION); +session_write_close(); + + +--EXPECT-- +NULL +array(1) { + ["foo"]=> + int(1) +} +array(0) { +} From aa3bc57ac8807442ec707e6cd167ca246d2437e3 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Thu, 12 Feb 2015 15:53:32 +0800 Subject: [PATCH 015/104] Fixed mem issue (double free) --- php_memcached.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index a1ea6835..28675f14 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -1299,14 +1299,8 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke retry: if (!by_key) { status = memcached_set(m_obj->memc, str_key->val, str_key->len, payload, payload_len, expiration, flags); - if (!skey) { - zend_string_release(str_key); - } } else { status = memcached_set_by_key(m_obj->memc, server_key->val, server_key->len, str_key->val, str_key->len, payload, payload_len, expiration, flags); - if (!skey) { - zend_string_release(str_key); - } } if (php_memc_handle_error(i_obj, status) < 0) { From 4187e2277fa7469b0b8a67045083dde1950cecc0 Mon Sep 17 00:00:00 2001 From: Rasmus Lerdorf Date: Wed, 22 Apr 2015 23:37:53 -0700 Subject: [PATCH 016/104] No more ZEND_CTOR_MAKE_NULL --- php_memcached.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index 28675f14..1063b229 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -407,8 +407,7 @@ static PHP_METHOD(Memcached, __construct) zend_fcall_info fci = {0}; zend_fcall_info_cache fci_cache; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!f!S", &persistent_id, &fci, &fci_cache, &conn_str) == FAILURE) { - ZEND_CTOR_MAKE_NULL(); + if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "|S!f!S", &persistent_id, &fci, &fci_cache, &conn_str) == FAILURE) { return; } From 650b67c64ca8ac8bd140492fd1078015cb8eaa0b Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Sat, 27 Jun 2015 18:28:31 +0200 Subject: [PATCH 017/104] Update php_memcached.c --- php_memcached.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php_memcached.c b/php_memcached.c index 1063b229..9195bfcd 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -3119,7 +3119,7 @@ zend_bool s_serialize_value (enum memcached_serializer serializer, zval *value, #ifdef HAVE_MEMCACHED_MSGPACK case SERIALIZER_MSGPACK: php_msgpack_serialize(buf, value); - if (!buf->c) { + if (!buf->s) { php_error_docref(NULL, E_WARNING, "could not serialize value with msgpack"); return 0; } From 2af8314b36a4842c76c53be02550653a57445cf1 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Mon, 31 Aug 2015 17:47:08 +0100 Subject: [PATCH 018/104] moar tests passing --- php_memcached.c | 26 ++++++++++++------------- tests/clone.phpt | 5 ++++- tests/experimental/cas_invalid_key.phpt | 4 ++-- tests/experimental/delete_bykey.phpt | 4 ++-- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index 3a25a1a6..caf268cc 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -170,7 +170,7 @@ typedef struct { } php_memc_t; static inline php_memc_t *php_memc_fetch_object(zend_object *obj) { - return (php_memc_t *)((char *)(obj) - XtOffsetOf(php_memc_t, zo)); + return (php_memc_t *)((char *)obj - XtOffsetOf(php_memc_t, zo)); } #define Z_MEMC_OBJ_P(zv) php_memc_fetch_object(Z_OBJ_P(zv)); @@ -356,20 +356,17 @@ char *php_memc_printable_func (zend_fcall_info *fci, zend_fcall_info_cache *fci_ static zend_bool php_memcached_on_new_callback(zval *object, zend_fcall_info *fci, zend_fcall_info_cache *fci_cache, zend_string *persistent_id) { zend_bool ret = 1; - zval retval; - zval params[2]; + zval retval, id; if (persistent_id) { - ZVAL_STR(¶ms[1], persistent_id); + ZVAL_STR(&id, persistent_id); } else { - ZVAL_NULL(¶ms[1]); + ZVAL_NULL(&id); } - /* Call the cb */ - ZVAL_COPY(¶ms[0], object); + ZVAL_UNDEF(&retval); - fci->params = params; - fci->param_count = 2; + zend_fcall_info_argn(fci, 2, object, &id); fci->retval = &retval; fci->no_separation = 1; @@ -379,10 +376,12 @@ static zend_bool php_memcached_on_new_callback(zval *object, zend_fcall_info *fc efree (buf); ret = 0; } + + if (Z_TYPE(retval) != IS_UNDEF) + zval_ptr_dtor(&retval); + + zend_fcall_info_args_clear(fci, 1); - zval_ptr_dtor(¶ms[0]); - zval_ptr_dtor(¶ms[1]); - zval_ptr_dtor(&retval); return ret; } @@ -408,7 +407,6 @@ static PHP_METHOD(Memcached, __construct) zend_fcall_info_cache fci_cache; if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!f!S", &persistent_id, &fci, &fci_cache, &conn_str) == FAILURE) { - ZEND_CTOR_MAKE_NULL(); return; } @@ -3304,6 +3302,7 @@ zend_bool s_unserialize_value (enum memcached_serializer serializer, int val_typ PHP_VAR_UNSERIALIZE_INIT(var_hash); if (!php_var_unserialize(value, (const unsigned char **)&payload_tmp, (const unsigned char *)payload_tmp + payload_len, &var_hash)) { + zval_ptr_dtor(value); ZVAL_FALSE(value); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); php_error_docref(NULL, E_WARNING, "could not unserialize value"); @@ -3538,6 +3537,7 @@ static memcached_return php_memc_do_cache_callback(zval *zmemc_obj, zend_fcall_i fci->param_count = 4; result = zend_call_function(fci, fcc); + ZVAL_DUP(value, Z_REFVAL(z_val)); expiration = Z_REFVAL(z_expiration); if (result == SUCCESS && Z_TYPE(retval) != IS_UNDEF) { diff --git a/tests/clone.phpt b/tests/clone.phpt index a0c49cd7..0b41c50c 100644 --- a/tests/clone.phpt +++ b/tests/clone.phpt @@ -12,4 +12,7 @@ $m = clone $m; echo "GOT HERE"; --EXPECTF-- -Fatal error: Trying to clone an uncloneable object of class Memcached in %s on line %d \ No newline at end of file +Fatal error: Uncaught Error: Trying to clone an uncloneable object of class Memcached in %s:6 +Stack trace: +#0 {main} + thrown in %s on line 6 diff --git a/tests/experimental/cas_invalid_key.phpt b/tests/experimental/cas_invalid_key.phpt index c01d2c8d..3a69e40e 100644 --- a/tests/experimental/cas_invalid_key.phpt +++ b/tests/experimental/cas_invalid_key.phpt @@ -11,11 +11,11 @@ error_reporting(0); var_dump($m->cas(0, '', true, 10)); echo $m->getResultMessage(), "\n"; -var_dump($m->cas(0, ' äö jas kjjhask d ', true, 10)); +var_dump($m->cas(0, ' äö jas kjjhask d ', true, 10)); # no spaces allowed echo $m->getResultMessage(), "\n"; --EXPECTF-- bool(false) A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE bool(false) -%rCLIENT ERROR|NOT FOUND%r +A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE diff --git a/tests/experimental/delete_bykey.phpt b/tests/experimental/delete_bykey.phpt index 87219539..9a198f15 100644 --- a/tests/experimental/delete_bykey.phpt +++ b/tests/experimental/delete_bykey.phpt @@ -21,7 +21,7 @@ var_dump($m->deleteByKey('keffe', '')); echo $m->getResultMessage(), "\n"; var_dump($m->deleteByKey('', 'keffe')); echo $m->getResultMessage(), "\n"; -var_dump($m->deleteByKey('keffe', 'äöåasäö åaösdäf asdf')); +var_dump($m->deleteByKey('keffe', 'äöåasäö åaösdäf asdf')); # no spaces allowed echo $m->getResultMessage(), "\n"; --EXPECTF-- string(3) "foo" @@ -37,4 +37,4 @@ A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE bool(false) NOT FOUND bool(false) -%rPROTOCOL ERROR|NOT FOUND|WRITE FAILURE|CLIENT ERROR%r +A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE From 20636b2ae39a9c17d0e5b955770746a82b2bf4bb Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Mon, 31 Aug 2015 18:22:15 +0100 Subject: [PATCH 019/104] down to four failures ... --- php_memcached.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index caf268cc..0c278505 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -3582,6 +3582,7 @@ static memcached_return php_memc_do_cache_callback(zval *zmemc_obj, zend_fcall_i zval_ptr_dtor(&z_key); zval_ptr_dtor(&z_val); zval_ptr_dtor(&z_expiration); + zval_ptr_dtor(zmemc_obj); return status; } @@ -3603,9 +3604,7 @@ static int php_memc_do_result_callback(zval *zmemc_obj, zend_fcall_info *fci, int rc = 0; php_memc_t *i_obj = NULL; - ZVAL_COPY(¶ms[0], zmemc_obj); fci->retval = &retval; - fci->params = params; fci->param_count = 2; payload = memcached_result_value(result); @@ -3624,7 +3623,6 @@ static int php_memc_do_result_callback(zval *zmemc_obj, zend_fcall_info *fci, } array_init(&z_result); - ZVAL_COPY(¶ms[1], &z_result); add_assoc_stringl_ex(&z_result, ZEND_STRL("key"), (char *)res_key, res_key_len); add_assoc_zval_ex(&z_result, ZEND_STRL("value"), &value); if (cas != 0) { @@ -3634,16 +3632,19 @@ static int php_memc_do_result_callback(zval *zmemc_obj, zend_fcall_info *fci, add_assoc_long_ex(&z_result, ZEND_STRL("flags"), MEMC_VAL_GET_USER_FLAGS(flags)); } + ZVAL_UNDEF(&retval); + zend_fcall_info_argn(fci, 2, zmemc_obj, &z_result); + if (zend_call_function(fci, fcc) == FAILURE) { php_error_docref(NULL, E_WARNING, "could not invoke result callback"); rc = -1; } - if (&retval) { + if (Z_TYPE(retval) != IS_UNDEF) { zval_ptr_dtor(&retval); } - zval_ptr_dtor(¶ms[0]); - zval_ptr_dtor(¶ms[1]); + + zend_fcall_info_args_clear(fci, 1); zval_ptr_dtor(&z_result); return rc; From a335533ec8a4b6390196f5a1310f95aba8d37efc Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Mon, 31 Aug 2015 19:08:15 +0100 Subject: [PATCH 020/104] another test expecting the wrong thing, it seems --- tests/experimental/get.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/experimental/get.phpt b/tests/experimental/get.phpt index 34537fc4..67e0b8f3 100644 --- a/tests/experimental/get.phpt +++ b/tests/experimental/get.phpt @@ -30,4 +30,4 @@ A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE string(4) "asdf" SUCCESS bool(false) -NOT FOUND +A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE From 08cb8ff24caea581e97287de7c3427b67b20b1e6 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Tue, 1 Sep 2015 18:15:02 +0100 Subject: [PATCH 021/104] bring travis up --- .travis.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index d529cf50..04f90cec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,7 @@ language: php php: - - 5.5 - #- 5.4 - #- 5.3 + - 7.0 + env: - LIBMEMCACHED_VERSION=1.0.17 - LIBMEMCACHED_VERSION=1.0.16 From 3a8c8fd7a016460d683fc68591072fce0a5c0c04 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Tue, 1 Sep 2015 18:30:46 +0100 Subject: [PATCH 022/104] disable stuff not available for 7 yet --- .travis/travis.sh | 10 +++++----- php_memcached.c | 2 +- tests/bad_construct.phpt | 13 ++++++++----- tests/experimental/get_bykey_cas.phpt | 2 +- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/.travis/travis.sh b/.travis/travis.sh index f90cae9f..bda8646e 100755 --- a/.travis/travis.sh +++ b/.travis/travis.sh @@ -155,11 +155,11 @@ function run_memcached_tests() { pushd "${PHP_MEMCACHED_BUILD_DIR}/memcached-${PHP_MEMCACHED_VERSION}" # We have one xfail test, we run it separately - php run-tests.php -d extension=msgpack.so -d extension=igbinary.so -d extension=memcached.so -n ./tests/expire.phpt + php run-tests.php -d extension=memcached.so -n ./tests/expire.phpt rm ./tests/expire.phpt # Run normal tests - php run-tests.php -d extension=msgpack.so -d extension=igbinary.so -d extension=memcached.so -n ./tests/*.phpt + php run-tests.php -d extension=memcached.so -n ./tests/*.phpt retval=$? for i in `ls tests/*.out 2>/dev/null`; do echo "-- START ${i}"; @@ -213,14 +213,14 @@ case $ACTION in install_libmemcached # Install igbinary extension - install_igbinary + # install_igbinary # install msgpack - install_msgpack + # install_msgpack # install SASL if test "x$ENABLE_SASL" = "xyes"; then - install_sasl + # install_sasl fi ;; diff --git a/php_memcached.c b/php_memcached.c index 1cd97550..926db8a4 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -406,7 +406,7 @@ static PHP_METHOD(Memcached, __construct) zend_fcall_info fci = {0}; zend_fcall_info_cache fci_cache; - if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "|S!f!S", &persistent_id, &fci, &fci_cache, &conn_str) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!f!S", &persistent_id, &fci, &fci_cache, &conn_str) == FAILURE) { return; } diff --git a/tests/bad_construct.phpt b/tests/bad_construct.phpt index 06bc7236..ab3079cf 100644 --- a/tests/bad_construct.phpt +++ b/tests/bad_construct.phpt @@ -4,7 +4,7 @@ Memcached construct with bad arguments --FILE-- setOption (Memcached::OPT_BINARY_PROTOCOL, true)); echo "OK" . PHP_EOL; --EXPECTF-- -Memcached::__construct() expects parameter %s -NULL +Warning: Memcached::__construct() expects parameter 1 to be string, object given in %s on line 3 +Memcached::__construct() expects parameter 1 to be string, object given +object(Memcached)#1 (0) { +} -Warning: Memcached::setOption(): Memcached constructor was not called in %s on line %d +Warning: Memcached::setOption(): Memcached constructor was not called in %s on line 14 NULL -OK \ No newline at end of file +OK + diff --git a/tests/experimental/get_bykey_cas.phpt b/tests/experimental/get_bykey_cas.phpt index ad94013e..6990927b 100644 --- a/tests/experimental/get_bykey_cas.phpt +++ b/tests/experimental/get_bykey_cas.phpt @@ -59,7 +59,7 @@ string(4) "asdf" float(%d) SUCCESS bool(false) -NULL +float(0) NOT FOUND bool(false) NULL From aaed3531e56d9d785e158645fdd47ebe6a7cd31c Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Tue, 1 Sep 2015 18:34:27 +0100 Subject: [PATCH 023/104] some stabbing in the dark, why not --- .travis/travis.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis/travis.sh b/.travis/travis.sh index bda8646e..04f2603a 100755 --- a/.travis/travis.sh +++ b/.travis/travis.sh @@ -128,8 +128,9 @@ function build_php_memcached() { sasl_flag="--enable-memcached-sasl" fi - ./configure --with-libmemcached-dir="$LIBMEMCACHED_PREFIX" $protocol_flag $sasl_flag --enable-memcached-json --enable-memcached-igbinary --enable-memcached-msgpack - make + # ./configure --with-libmemcached-dir="$LIBMEMCACHED_PREFIX" $protocol_flag $sasl_flag --enable-memcached-json --enable-memcached-igbinary --enable-memcached-msgpack + ./configure --with-libmemcached-dir="$LIBMEMCACHED_PREFIX" $protocol_flag $sasl_flag + make make install popd } @@ -220,7 +221,7 @@ case $ACTION in # install SASL if test "x$ENABLE_SASL" = "xyes"; then - # install_sasl + install_sasl fi ;; From d354bf6551bc070e0c6374df8cadbc2c9e9f13df Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Tue, 1 Sep 2015 19:07:42 +0100 Subject: [PATCH 024/104] update test to skip in appropriate versions (make travis more useful) --- tests/gh_155.phpt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/gh_155.phpt b/tests/gh_155.phpt index c1f02bc6..2e7f5643 100644 --- a/tests/gh_155.phpt +++ b/tests/gh_155.phpt @@ -1,7 +1,12 @@ --TEST-- Test for bug 155 --SKIPIF-- - + --FILE-- Date: Tue, 1 Sep 2015 19:12:52 +0100 Subject: [PATCH 025/104] omg, I'm a fumbling idiot --- tests/gh_155.phpt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/gh_155.phpt b/tests/gh_155.phpt index 2e7f5643..643085ae 100644 --- a/tests/gh_155.phpt +++ b/tests/gh_155.phpt @@ -2,10 +2,9 @@ Test for bug 155 --SKIPIF-- --FILE-- Date: Tue, 1 Sep 2015 20:45:47 +0100 Subject: [PATCH 026/104] fix json support --- .travis/travis.sh | 5 +++-- config.m4 | 30 +++--------------------------- php_memcached.c | 21 +++------------------ 3 files changed, 9 insertions(+), 47 deletions(-) diff --git a/.travis/travis.sh b/.travis/travis.sh index 04f2603a..f045e594 100755 --- a/.travis/travis.sh +++ b/.travis/travis.sh @@ -73,6 +73,7 @@ function install_igbinary() { function install_msgpack() { git clone https://github.com/msgpack/msgpack-php.git pushd msgpack-php + git checkout php7 phpize ./configure make @@ -128,8 +129,8 @@ function build_php_memcached() { sasl_flag="--enable-memcached-sasl" fi - # ./configure --with-libmemcached-dir="$LIBMEMCACHED_PREFIX" $protocol_flag $sasl_flag --enable-memcached-json --enable-memcached-igbinary --enable-memcached-msgpack - ./configure --with-libmemcached-dir="$LIBMEMCACHED_PREFIX" $protocol_flag $sasl_flag + # ./configure --with-libmemcached-dir="$LIBMEMCACHED_PREFIX" $protocol_flag $sasl_flag --enable-memcached-igbinary --enable-memcached-msgpack + ./configure --with-libmemcached-dir="$LIBMEMCACHED_PREFIX" $protocol_flag $sasl_flag --enable-memcached-json make make install popd diff --git a/config.m4 b/config.m4 index 107f8cbe..ec1e4ae8 100644 --- a/config.m4 +++ b/config.m4 @@ -127,7 +127,7 @@ if test "$PHP_MEMCACHED" != "no"; then PHP_MEMCACHED_VERSION_MASK=`echo ${PHP_MEMCACHED_VERSION_ORIG} | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'` - if test $PHP_MEMCACHED_VERSION_MASK -ge 5003000; then + if test $PHP_MEMCACHED_VERSION_MASK -ge 7000000; then if test -f "$abs_srcdir/include/php/ext/json/php_json.h"; then json_inc_path="$abs_srcdir/include/php" elif test -f "$abs_srcdir/ext/json/php_json.h"; then @@ -145,33 +145,9 @@ if test "$PHP_MEMCACHED" != "no"; then AC_MSG_ERROR([Cannot find php_json.h]) else AC_DEFINE(HAVE_JSON_API,1,[Whether JSON API is available]) - AC_DEFINE(HAVE_JSON_API_5_3,1,[Whether JSON API for PHP 5.3 is available]) - AC_MSG_RESULT([$json_inc_path]) fi - elif test $PHP_MEMCACHED_VERSION_MASK -ge 5002009; then - dnl Check JSON for PHP 5.2.9+ - if test -f "$abs_srcdir/include/php/ext/json/php_json.h"; then - json_inc_path="$abs_srcdir/include/php" - elif test -f "$abs_srcdir/ext/json/php_json.h"; then - json_inc_path="$abs_srcdir" - elif test -f "$phpincludedir/ext/json/php_json.h"; then - json_inc_path="$phpincludedir" - else - for i in php php4 php5 php6; do - if test -f "$prefix/include/$i/ext/json/php_json.h"; then - json_inc_path="$prefix/include/$i" - fi - done - fi - if test "$json_inc_path" = ""; then - AC_MSG_ERROR([Cannot find php_json.h]) - else - AC_DEFINE(HAVE_JSON_API,1,[Whether JSON API is available]) - AC_DEFINE(HAVE_JSON_API_5_2,1,[Whether JSON API for PHP 5.2 is available]) - AC_MSG_RESULT([$json_inc_path]) - fi - else - AC_MSG_RESULT([the PHP version does not support JSON serialization API]) + else + AC_MSG_RESULT([this version of memcached is only suitable for PHP7+]) fi fi diff --git a/php_memcached.c b/php_memcached.c index 926db8a4..9f65e52f 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -37,7 +37,7 @@ #endif #include -#ifdef HAVE_JSON_API +#ifdef HAVE_JSON # include "ext/json/php_json.h" #endif @@ -49,13 +49,6 @@ # include "ext/msgpack/php_msgpack.h" #endif -/* - * This is needed because PHP 5.3.[01] does not install JSON_parser.h by default. This - * constant will move into php_json.h in the future anyway. - */ -#ifndef JSON_PARSER_DEFAULT_DEPTH -#define JSON_PARSER_DEFAULT_DEPTH 512 -#endif /**************************************** Custom options @@ -3102,11 +3095,7 @@ zend_bool s_serialize_value (enum memcached_serializer serializer, zval *value, case SERIALIZER_JSON: case SERIALIZER_JSON_ARRAY: { -#if HAVE_JSON_API_5_2 - php_json_encode(buf, value); -#elif HAVE_JSON_API_5_3 - php_json_encode(buf, value, 0); /* options */ -#endif + php_json_encode(buf, value, 0); MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_JSON); } break; @@ -3320,11 +3309,7 @@ zend_bool s_unserialize_value (enum memcached_serializer serializer, int val_typ case MEMC_VAL_IS_JSON: #ifdef HAVE_JSON_API -# if HAVE_JSON_API_5_2 - php_json_decode(value, payload, payload_len, (serializer == SERIALIZER_JSON_ARRAY)); -# elif HAVE_JSON_API_5_3 - php_json_decode(value, payload, payload_len, (serializer == SERIALIZER_JSON_ARRAY), JSON_PARSER_DEFAULT_DEPTH); -# endif + php_json_decode(value, payload, payload_len, ,(serializer == SERIALIZER_JSON_ARRAY), JSON_PARSER_DEFAULT_DEPTH); #else ZVAL_FALSE(value); php_error_docref(NULL, E_WARNING, "could not unserialize value, no json support"); From b04d020aa7accfa51b1f552bcb9a2f44e45d1a7c Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Tue, 1 Sep 2015 20:52:00 +0100 Subject: [PATCH 027/104] minor woops --- php_memcached.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php_memcached.c b/php_memcached.c index 9f65e52f..fb68274a 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -37,7 +37,7 @@ #endif #include -#ifdef HAVE_JSON +#ifdef HAVE_JSON_API # include "ext/json/php_json.h" #endif From 2f5a5b06b1296f081148eafa1d08c89b2b035ab8 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Tue, 1 Sep 2015 21:25:01 +0100 Subject: [PATCH 028/104] woops --- config.m4 | 1 + php_memcached.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/config.m4 b/config.m4 index ec1e4ae8..a4bbda4e 100644 --- a/config.m4 +++ b/config.m4 @@ -145,6 +145,7 @@ if test "$PHP_MEMCACHED" != "no"; then AC_MSG_ERROR([Cannot find php_json.h]) else AC_DEFINE(HAVE_JSON_API,1,[Whether JSON API is available]) + AC_MSG_RESULT([$json_inc_path]) fi else AC_MSG_RESULT([this version of memcached is only suitable for PHP7+]) diff --git a/php_memcached.c b/php_memcached.c index fb68274a..a6c338b8 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -3309,7 +3309,7 @@ zend_bool s_unserialize_value (enum memcached_serializer serializer, int val_typ case MEMC_VAL_IS_JSON: #ifdef HAVE_JSON_API - php_json_decode(value, payload, payload_len, ,(serializer == SERIALIZER_JSON_ARRAY), JSON_PARSER_DEFAULT_DEPTH); + php_json_decode(value, (char*) payload, payload_len, (serializer == SERIALIZER_JSON_ARRAY), PHP_JSON_PARSER_DEFAULT_DEPTH); #else ZVAL_FALSE(value); php_error_docref(NULL, E_WARNING, "could not unserialize value, no json support"); From a24e439cb6f9c38d1a51c0df2cf6dab79e0a14bc Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Wed, 2 Sep 2015 08:06:48 +0100 Subject: [PATCH 029/104] tidy configure stuff for json --- .travis/travis.sh | 4 ++-- config.m4 | 54 +++++++++++++++-------------------------------- tests/types.inc | 5 +++-- 3 files changed, 22 insertions(+), 41 deletions(-) diff --git a/.travis/travis.sh b/.travis/travis.sh index f045e594..e6733526 100755 --- a/.travis/travis.sh +++ b/.travis/travis.sh @@ -129,8 +129,8 @@ function build_php_memcached() { sasl_flag="--enable-memcached-sasl" fi - # ./configure --with-libmemcached-dir="$LIBMEMCACHED_PREFIX" $protocol_flag $sasl_flag --enable-memcached-igbinary --enable-memcached-msgpack - ./configure --with-libmemcached-dir="$LIBMEMCACHED_PREFIX" $protocol_flag $sasl_flag --enable-memcached-json + # ./configure --with-libmemcached-dir="$LIBMEMCACHED_PREFIX" $protocol_flag $sasl_flag --enable-memcached-json --enable-memcached-msgpack --enable-memcached-igbinary + ./configure --with-libmemcached-dir="$LIBMEMCACHED_PREFIX" $protocol_flag $sasl_flag make make install popd diff --git a/config.m4 b/config.m4 index a4bbda4e..48efd176 100644 --- a/config.m4 +++ b/config.m4 @@ -106,49 +106,29 @@ if test "$PHP_MEMCACHED" != "no"; then AC_MSG_RESULT([$session_inc_path]) fi fi - + if test "$PHP_MEMCACHED_JSON" != "no"; then AC_MSG_CHECKING([for json includes]) json_inc_path="" - - tmp_version=$PHP_VERSION - if test -z "$tmp_version"; then - if test -z "$PHP_CONFIG"; then - AC_MSG_ERROR([php-config not found]) - fi - PHP_MEMCACHED_VERSION_ORIG=`$PHP_CONFIG --version`; - else - PHP_MEMCACHED_VERSION_ORIG=$tmp_version - fi - if test -z $PHP_MEMCACHED_VERSION_ORIG; then - AC_MSG_ERROR([failed to detect PHP version, please report]) + if test -f "$abs_srcdir/include/php/ext/json/php_json.h"; then + json_inc_path="$abs_srcdir/include/php" + elif test -f "$abs_srcdir/ext/json/php_json.h"; then + json_inc_path="$abs_srcdir" + elif test -f "$phpincludedir/ext/json/php_json.h"; then + json_inc_path="$phpincludedir" + else + for i in php php4 php5 php6; do + if test -f "$prefix/include/$i/ext/json/php_json.h"; then + json_inc_path="$prefix/include/$i" + fi + done fi - - PHP_MEMCACHED_VERSION_MASK=`echo ${PHP_MEMCACHED_VERSION_ORIG} | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'` - - if test $PHP_MEMCACHED_VERSION_MASK -ge 7000000; then - if test -f "$abs_srcdir/include/php/ext/json/php_json.h"; then - json_inc_path="$abs_srcdir/include/php" - elif test -f "$abs_srcdir/ext/json/php_json.h"; then - json_inc_path="$abs_srcdir" - elif test -f "$phpincludedir/ext/json/php_json.h"; then - json_inc_path="$phpincludedir" - else - for i in php php4 php5 php6; do - if test -f "$prefix/include/$i/ext/json/php_json.h"; then - json_inc_path="$prefix/include/$i" - fi - done - fi - if test "$json_inc_path" = ""; then - AC_MSG_ERROR([Cannot find php_json.h]) - else - AC_DEFINE(HAVE_JSON_API,1,[Whether JSON API is available]) - AC_MSG_RESULT([$json_inc_path]) - fi + if test "$json_inc_path" = ""; then + AC_MSG_ERROR([Cannot find php_json.h]) else - AC_MSG_RESULT([this version of memcached is only suitable for PHP7+]) + AC_DEFINE(HAVE_JSON_API,1,[Whether JSON API is available]) + AC_MSG_RESULT([$json_inc_path]) fi fi diff --git a/tests/types.inc b/tests/types.inc index 5e0ad5d3..9532c8fc 100644 --- a/tests/types.inc +++ b/tests/types.inc @@ -54,11 +54,12 @@ function memc_types_test ($m, $options) if ($value == $actual && get_class($value) == get_class($actual)) continue; } - echo "=== $types[0] ===\n"; + echo "=== {$key} ===\n"; echo "Expected: "; - var_dump($types[1]); + var_dump($value); echo "Actual: "; var_dump($actual); + } } From 23db27a09ba3b35756305aa5bf487a9e530e9166 Mon Sep 17 00:00:00 2001 From: Alex Samorukov Date: Thu, 12 Nov 2015 23:20:44 +0100 Subject: [PATCH 030/104] check if session was allocated on PS_OPEN_FUNC --- php_memcached_session.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/php_memcached_session.c b/php_memcached_session.c index 1d2dbe32..b04cd925 100644 --- a/php_memcached_session.c +++ b/php_memcached_session.c @@ -277,6 +277,11 @@ PS_OPEN_FUNC(memcached) PS_CLOSE_FUNC(memcached) { memcached_sess *memc_sess = PS_GET_MOD_DATA(); + + if (!memc_sess) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session is not allocated, check session.save_path value"); + return FAILURE; + } if (MEMC_G(sess_locking_enabled)) { php_memc_sess_unlock(memc_sess->memc_sess); @@ -307,6 +312,11 @@ PS_READ_FUNC(memcached) memcached_sess *memc_sess = PS_GET_MOD_DATA(); size_t key_length; + if (!memc_sess) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session is not allocated, check session.save_path value"); + return FAILURE; + } + key_length = strlen(MEMC_G(sess_prefix)) + key_len + 5; // prefix + "lock." if (!key_length || key_length >= MEMCACHED_MAX_KEY) { php_error_docref(NULL, E_WARNING, "The session id is too long or contains illegal characters"); @@ -339,6 +349,11 @@ PS_WRITE_FUNC(memcached) memcached_return status; memcached_sess *memc_sess = PS_GET_MOD_DATA(); size_t key_length; + + if (!memc_sess) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session is not allocated, check session.save_path value"); + return FAILURE; + } key_length = strlen(MEMC_G(sess_prefix)) + key_len + 5; // prefix + "lock." if (!key_length || key_length >= MEMCACHED_MAX_KEY) { @@ -371,6 +386,11 @@ PS_DESTROY_FUNC(memcached) { memcached_sess *memc_sess = PS_GET_MOD_DATA(); + if (!memc_sess) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session is not allocated, check session.save_path value"); + return FAILURE; + } + memcached_delete(memc_sess->memc_sess, key->val, key->len, 0); if (MEMC_G(sess_locking_enabled)) { php_memc_sess_unlock(memc_sess->memc_sess); From fb8ce9e3cbfdacb50dc8b916e8502bb9e58d2e20 Mon Sep 17 00:00:00 2001 From: Will Gallego Date: Tue, 17 Nov 2015 20:52:04 +0000 Subject: [PATCH 031/104] removing unused var, fixing smart_str use w/ igbinary --- php_memcached.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index a6c338b8..a96a2aed 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -3080,7 +3080,7 @@ zend_bool s_serialize_value (enum memcached_serializer serializer, zval *value, */ #ifdef HAVE_MEMCACHED_IGBINARY case SERIALIZER_IGBINARY: - if (igbinary_serialize((uint8_t **) &buf->c, &buf->len, value) != 0) { + if (igbinary_serialize((uint8_t **) &(buf->s), &buf->s->len, value) != 0) { php_error_docref(NULL, E_WARNING, "could not serialize value with igbinary"); return 0; } @@ -3575,7 +3575,6 @@ static int php_memc_do_result_callback(zval *zmemc_obj, zend_fcall_info *fci, zval value; zval retval; uint64_t cas = 0; - zval params[2]; zval z_result; uint32_t flags = 0; int rc = 0; From b5a58cd207ca50df9288ba124c37fda65e1e1d4b Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Wed, 16 Dec 2015 13:42:28 +0000 Subject: [PATCH 032/104] remove duplicate class constant registration --- php_memcached.c | 1 - 1 file changed, 1 deletion(-) diff --git a/php_memcached.c b/php_memcached.c index a6c338b8..72637d1c 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -4319,7 +4319,6 @@ static void php_memc_register_constants(INIT_FUNC_ARGS) REGISTER_MEMC_CLASS_CONST_LONG(RES_MEMORY_ALLOCATION_FAILURE, MEMCACHED_MEMORY_ALLOCATION_FAILURE); REGISTER_MEMC_CLASS_CONST_LONG(RES_CONNECTION_SOCKET_CREATE_FAILURE, MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE); - REGISTER_MEMC_CLASS_CONST_LONG(RES_BAD_KEY_PROVIDED, MEMCACHED_BAD_KEY_PROVIDED); REGISTER_MEMC_CLASS_CONST_LONG(RES_E2BIG, MEMCACHED_E2BIG); REGISTER_MEMC_CLASS_CONST_LONG(RES_KEY_TOO_BIG, MEMCACHED_KEY_TOO_BIG); REGISTER_MEMC_CLASS_CONST_LONG(RES_SERVER_TEMPORARILY_DISABLED, MEMCACHED_SERVER_TEMPORARILY_DISABLED); From bd321830676d7e313b4b39bec6fbeb6ec9f9f7d8 Mon Sep 17 00:00:00 2001 From: Yasuo Ohgaki Date: Sat, 16 Jan 2016 06:19:50 +0900 Subject: [PATCH 033/104] Fixed session read return value --- php_memcached_session.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php_memcached_session.c b/php_memcached_session.c index 4d1a2572..59b12467 100644 --- a/php_memcached_session.c +++ b/php_memcached_session.c @@ -326,6 +326,8 @@ PS_READ_FUNC(memcached) *val = zend_string_init(payload, payload_len, 1); free(payload); return SUCCESS; + } else if (status = MEMCACHED_NOTFOUND) { + *val = ZSTR_EMPTY_ALLOC(); } else { return FAILURE; } From 9e11ffa8e5d5e6b1256dc44b7f043e7114122170 Mon Sep 17 00:00:00 2001 From: Mikko Date: Sat, 16 Jan 2016 21:40:35 +0000 Subject: [PATCH 034/104] Revert the user flags and move into Memcached::getLastUserFlags --- php_memcached.c | 194 +++++++++++++++++++++--------------------- tests/user-flags.phpt | 72 +++++++++++----- 2 files changed, 148 insertions(+), 118 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index a6c338b8..1339f308 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -58,6 +58,7 @@ #define MEMC_OPT_SERIALIZER -1003 #define MEMC_OPT_COMPRESSION_TYPE -1004 #define MEMC_OPT_STORE_RETRY_COUNT -1005 +#define MEMC_OPT_USER_FLAGS -1006 /**************************************** Custom result codes @@ -153,8 +154,10 @@ typedef struct { zend_bool has_sasl_data; #endif long store_retry_count; + zend_long set_udf_flags; } *obj; + zval last_udf_flags; zend_bool is_persistent; zend_bool is_pristine; int rescode; @@ -466,6 +469,9 @@ static PHP_METHOD(Memcached, __construct) m_obj->compression = 1; m_obj->store_retry_count = MEMC_G(store_retry_count); + m_obj->set_udf_flags = -1; + array_init(&i_obj->last_udf_flags); + i_obj->obj = m_obj; i_obj->is_pristine = 1; @@ -508,7 +514,23 @@ static PHP_METHOD(Memcached, __construct) } /* }}} */ -/* {{{ Memcached::get(string key [, mixed callback [, double &cas_token [, int &udf_flags ] ] ]) +/* {{{ Memcached::getLastUserFlags() + Returns the user flags from last fetch operation */ +PHP_METHOD(Memcached, getLastUserFlags) +{ + MEMC_METHOD_INIT_VARS; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + MEMC_METHOD_FETCH_OBJECT; + RETVAL_ZVAL(&i_obj->last_udf_flags, 1, 0); +} +/* }}} */ + + +/* {{{ Memcached::get(string key [, mixed callback [, double &cas_token ] ]) Returns a value for the given key or false */ PHP_METHOD(Memcached, get) { @@ -516,7 +538,7 @@ PHP_METHOD(Memcached, get) } /* }}} */ -/* {{{ Memcached::getByKey(string server_key, string key [, mixed callback [, double &cas_token [, int &udf_flags ] ] ]) +/* {{{ Memcached::getByKey(string server_key, string key [, mixed callback [, double &cas_token ] ]) Returns a value for key from the server identified by the server key or false */ PHP_METHOD(Memcached, getByKey) { @@ -536,7 +558,6 @@ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) const char* keys[1] = { NULL }; size_t key_lens[1] = { 0 }; zval *cas_token = NULL; - zval *udf_flags = NULL; uint64_t orig_cas_flag; zend_fcall_info fci = empty_fcall_info; zend_fcall_info_cache fcc = empty_fcall_info_cache; @@ -545,13 +566,11 @@ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) MEMC_METHOD_INIT_VARS; if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|f!zz", &server_key, &key, - &fci, &fcc, &cas_token, &udf_flags) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|f!z", &server_key, &key, &fci, &fcc, &cas_token) == FAILURE) { return; } } else { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|f!zz", &key, - &fci, &fcc, &cas_token, &udf_flags) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|f!z", &key, &fci, &fcc, &cas_token) == FAILURE) { return; } } @@ -559,7 +578,9 @@ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) MEMC_METHOD_FETCH_OBJECT; i_obj->rescode = MEMCACHED_SUCCESS; - if (key->len == 0 || strchr(key->val, ' ')) { + zend_hash_clean(Z_ARRVAL(i_obj->last_udf_flags)); + + if (key->len == 0) { i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; RETURN_FROM_GET; } @@ -650,18 +671,13 @@ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) ZVAL_DOUBLE(cas_token, (double)cas); } - if (udf_flags) { - ZVAL_DEREF(udf_flags); - SEPARATE_ZVAL(udf_flags); - zval_dtor(udf_flags); - ZVAL_LONG(udf_flags, MEMC_VAL_GET_USER_FLAGS(flags)); - } - + /* Parse user flags */ + add_assoc_long_ex(&i_obj->last_udf_flags, key->val, key->len, MEMC_VAL_GET_USER_FLAGS(flags)); memcached_result_free(&result); } /* }}} */ -/* {{{ Memcached::getMulti(array keys [, array &cas_tokens [, array &udf_flags ] ]) +/* {{{ Memcached::getMulti(array keys [, array &cas_tokens ]) Returns values for the given keys or false */ PHP_METHOD(Memcached, getMulti) { @@ -669,7 +685,7 @@ PHP_METHOD(Memcached, getMulti) } /* }}} */ -/* {{{ Memcached::getMultiByKey(string server_key, array keys [, array &cas_tokens [, array &udf_flags ] ]) +/* {{{ Memcached::getMultiByKey(string server_key, array keys [, array &cas_tokens ]) Returns values for the given keys from the server identified by the server key or false */ PHP_METHOD(Memcached, getMultiByKey) { @@ -693,7 +709,6 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke uint32_t flags; uint64_t cas = 0; zval *cas_tokens = NULL; - zval *udf_flags = NULL; uint64_t orig_cas_flag = 0; zval value; long get_flags = 0; @@ -704,12 +719,12 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke MEMC_METHOD_INIT_VARS; if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa/|zlz", &server_key, - &keys, &cas_tokens, &get_flags, &udf_flags) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa/|zl", &server_key, + &keys, &cas_tokens, &get_flags) == FAILURE) { return; } } else { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|zlz", &keys, &cas_tokens, &get_flags, &udf_flags) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|zl", &keys, &cas_tokens, &get_flags) == FAILURE) { return; } } @@ -717,6 +732,9 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke MEMC_METHOD_FETCH_OBJECT; i_obj->rescode = MEMCACHED_SUCCESS; + /* clean flags */ + zend_hash_clean(Z_ARRVAL(i_obj->last_udf_flags)); + preserve_order = (get_flags & MEMC_GET_PRESERVE_ORDER); num_keys = zend_hash_num_elements(Z_ARRVAL_P(keys)); mkeys = safe_emalloc(num_keys, sizeof(*mkeys), 0); @@ -801,12 +819,6 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke * Iterate through the result set and create the result array. The flags are * returned as longs. */ - if (udf_flags) { - ZVAL_DEREF(udf_flags); - SEPARATE_ZVAL(udf_flags); - zval_dtor(udf_flags); - array_init(udf_flags); - } memcached_result_create(m_obj->memc, &result); while ((memcached_fetch_result(m_obj->memc, &result, &status)) != NULL) { @@ -851,9 +863,7 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke cas = memcached_result_cas(&result); add_assoc_double_ex(cas_tokens, res_key, res_key_len, (double)cas); } - if (udf_flags) { - add_assoc_long_ex(udf_flags, res_key, res_key_len, MEMC_VAL_GET_USER_FLAGS(flags)); - } + add_assoc_long_ex(&i_obj->last_udf_flags, res_key, res_key_len, MEMC_VAL_GET_USER_FLAGS(flags)); } memcached_result_free(&result); @@ -866,12 +876,7 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke zval_dtor(cas_tokens); ZVAL_NULL(cas_tokens); } - if (udf_flags) { - ZVAL_DEREF(udf_flags); - SEPARATE_ZVAL(udf_flags); - zval_dtor(udf_flags); - ZVAL_NULL(udf_flags); - } + zend_hash_clean(Z_ARRVAL(i_obj->last_udf_flags)); zval_dtor(return_value); RETURN_FALSE; } @@ -1136,7 +1141,7 @@ PHP_METHOD(Memcached, fetchAll) } /* }}} */ -/* {{{ Memcached::set(string key, mixed value [, int expiration [, int udf_flags ] ]) +/* {{{ Memcached::set(string key, mixed value [, int expiration ]) Sets the value for the given key */ PHP_METHOD(Memcached, set) { @@ -1144,7 +1149,7 @@ PHP_METHOD(Memcached, set) } /* }}} */ -/* {{{ Memcached::setByKey(string server_key, string key, mixed value [, int expiration [, int udf_flags ] ]) +/* {{{ Memcached::setByKey(string server_key, string key, mixed value [, int expiration ]) Sets the value for the given key on the server identified by the server key */ PHP_METHOD(Memcached, setByKey) { @@ -1171,7 +1176,7 @@ PHP_METHOD(Memcached, touchByKey) #endif -/* {{{ Memcached::setMulti(array items [, int expiration [, int udf_flags ] ]) +/* {{{ Memcached::setMulti(array items [, int expiration ]) Sets the keys/values specified in the items array */ PHP_METHOD(Memcached, setMulti) { @@ -1179,7 +1184,7 @@ PHP_METHOD(Memcached, setMulti) } /* }}} */ -/* {{{ Memcached::setMultiByKey(string server_key, array items [, int expiration [, int udf_flags ] ]) +/* {{{ Memcached::setMultiByKey(string server_key, array items [, int expiration ]) Sets the keys/values specified in the items array on the server identified by the given server key */ PHP_METHOD(Memcached, setMultiByKey) { @@ -1218,7 +1223,6 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke zval *entries; zend_string *server_key = NULL; time_t expiration = 0; - long udf_flags = 0; zval *entry; zend_string *skey, *str_key = NULL; ulong num_key; @@ -1233,11 +1237,11 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke if (by_key) { if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa|ll", &server_key, - &entries, &expiration, &udf_flags) == FAILURE) { + &entries, &expiration) == FAILURE) { return; } } else { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|ll", &entries, &expiration, &udf_flags) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|ll", &entries, &expiration) == FAILURE) { return; } } @@ -1245,16 +1249,6 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke MEMC_METHOD_FETCH_OBJECT; i_obj->rescode = MEMCACHED_SUCCESS; - /* - * php_memcached uses 16 bits internally to store type, compression and serialization info. - * We use 16 upper bits to store user defined flags. - */ - if (udf_flags > 0) { - if ((uint32_t) udf_flags > MEMC_VAL_USER_FLAGS_MAX) { - php_error_docref(NULL, E_WARNING, "udf_flags will be limited to %u", MEMC_VAL_USER_FLAGS_MAX); - } - } - ZEND_HASH_FOREACH_KEY_VAL (Z_ARRVAL_P(entries), num_key, skey, entry) { if (skey) { str_key = skey; @@ -1274,8 +1268,8 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke MEMC_VAL_SET_FLAG(flags, MEMC_VAL_COMPRESSED); } - if (udf_flags > 0) { - MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) udf_flags)); + if (m_obj->set_udf_flags >= 0) { + MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) m_obj->set_udf_flags)); } payload = php_memc_zval_to_payload(entry, &payload_len, &flags, m_obj->serializer, m_obj->compression_type); @@ -1312,7 +1306,7 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke } /* }}} */ -/* {{{ Memcached::add(string key, mixed value [, int expiration [, int udf_flags ] ]) +/* {{{ Memcached::add(string key, mixed value [, int expiration ]) Sets the value for the given key, failing if the key already exists */ PHP_METHOD(Memcached, add) { @@ -1320,7 +1314,7 @@ PHP_METHOD(Memcached, add) } /* }}} */ -/* {{{ Memcached::addByKey(string server_key, string key, mixed value [, int expiration [, int udf_flags ] ]) +/* {{{ Memcached::addByKey(string server_key, string key, mixed value [, int expiration ]) Sets the value for the given key on the server identified by the sever key, failing if the key already exists */ PHP_METHOD(Memcached, addByKey) { @@ -1360,7 +1354,7 @@ PHP_METHOD(Memcached, prependByKey) } /* }}} */ -/* {{{ Memcached::replace(string key, mixed value [, int expiration [, int udf_flags ] ]) +/* {{{ Memcached::replace(string key, mixed value [, int expiration ]) Replaces the value for the given key, failing if the key doesn't exist */ PHP_METHOD(Memcached, replace) { @@ -1368,7 +1362,7 @@ PHP_METHOD(Memcached, replace) } /* }}} */ -/* {{{ Memcached::replaceByKey(string server_key, string key, mixed value [, int expiration [, int udf_flags ] ]) +/* {{{ Memcached::replaceByKey(string server_key, string key, mixed value [, int expiration ]) Replaces the value for the given key on the server identified by the server key, failing if the key doesn't exist */ PHP_METHOD(Memcached, replaceByKey) { @@ -1385,7 +1379,6 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool zval s_zvalue; zval *value; long expiration = 0; - long udf_flags = 0; char *payload = NULL; size_t payload_len; uint32_t flags = 0; @@ -1405,7 +1398,7 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool return; } } else { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSz|ll", &server_key, &key, &value, &expiration, &udf_flags) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSz|l", &server_key, &key, &value, &expiration) == FAILURE) { return; } } @@ -1421,7 +1414,7 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool return; } } else { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|ll", &key, &value, &expiration, &udf_flags) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|l", &key, &value, &expiration) == FAILURE) { return; } } @@ -1430,7 +1423,7 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool MEMC_METHOD_FETCH_OBJECT; i_obj->rescode = MEMCACHED_SUCCESS; - if (key->len == 0 || strchr(key->val, ' ')) { + if (key->len == 0) { i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; RETURN_FALSE; } @@ -1452,11 +1445,8 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool * php_memcached uses 16 bits internally to store type, compression and serialization info. * We use 16 upper bits to store user defined flags. */ - if (udf_flags > 0) { - if ((uint32_t) udf_flags > MEMC_VAL_USER_FLAGS_MAX) { - php_error_docref(NULL, E_WARNING, "udf_flags will be limited to %u", MEMC_VAL_USER_FLAGS_MAX); - } - MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) udf_flags)); + if (m_obj->set_udf_flags >= 0) { + MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) m_obj->set_udf_flags)); } if (op == MEMC_OP_TOUCH) { @@ -1557,7 +1547,6 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) zend_string *server_key = NULL; zval *value; time_t expiration = 0; - long udf_flags = 0; char *payload; size_t payload_len; uint32_t flags = 0; @@ -1566,12 +1555,12 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) if (by_key) { if (zend_parse_parameters(ZEND_NUM_ARGS(), "dSSz|ll", &cas_d, &server_key, &key, - &value, &expiration, &udf_flags) == FAILURE) { + &value, &expiration) == FAILURE) { return; } } else { if (zend_parse_parameters(ZEND_NUM_ARGS(), "dSz|ll", &cas_d, &key, &value, - &expiration, &udf_flags) == FAILURE) { + &expiration) == FAILURE) { return; } } @@ -1579,7 +1568,7 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) MEMC_METHOD_FETCH_OBJECT; i_obj->rescode = MEMCACHED_SUCCESS; - if (key->len == 0 || strchr(key->val, ' ')) { + if (key->len == 0) { i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; RETURN_FALSE; } @@ -1594,11 +1583,8 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) * php_memcached uses 16 bits internally to store type, compression and serialization info. * We use 16 upper bits to store user defined flags. */ - if (udf_flags > 0) { - if ((uint32_t) udf_flags > MEMC_VAL_USER_FLAGS_MAX) { - php_error_docref(NULL, E_WARNING, "udf_flags will be limited to %u", MEMC_VAL_USER_FLAGS_MAX); - } - MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) udf_flags)); + if (m_obj->set_udf_flags > 0) { + MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) m_obj->set_udf_flags)); } payload = php_memc_zval_to_payload(value, &payload_len, &flags, m_obj->serializer, m_obj->compression_type); @@ -1621,7 +1607,7 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) } /* }}} */ -/* {{{ Memcached::cas(double cas_token, string key, mixed value [, int expiration [, int udf_flags ] ]) +/* {{{ Memcached::cas(double cas_token, string key, mixed value [, int expiration ]) Sets the value for the given key, failing if the cas_token doesn't match the one in memcache */ PHP_METHOD(Memcached, cas) { @@ -1629,7 +1615,7 @@ PHP_METHOD(Memcached, cas) } /* }}} */ -/* {{{ Memcached::casByKey(double cas_token, string server_key, string key, mixed value [, int expiration [, int udf_flags ] ]) +/* {{{ Memcached::casByKey(double cas_token, string server_key, string key, mixed value [, int expiration ]) Sets the value for the given key on the server identified by the server_key, failing if the cas_token doesn't match the one in memcache */ PHP_METHOD(Memcached, casByKey) { @@ -2344,6 +2330,10 @@ static PHP_METHOD(Memcached, getOption) RETURN_LONG((long)m_obj->serializer); break; + case MEMC_OPT_USER_FLAGS: + RETURN_LONG(m_obj->set_udf_flags); + break; + case MEMC_OPT_STORE_RETRY_COUNT: RETURN_LONG((long)m_obj->store_retry_count); break; @@ -2481,6 +2471,21 @@ static int php_memc_set_option(php_memc_t *i_obj, long option, zval *value) break; } + case MEMC_OPT_USER_FLAGS: + convert_to_long(value); + + if (Z_LVAL_P(value) < 0) { + m_obj->set_udf_flags = -1; + return 1; + } + + if (Z_LVAL_P(value) > MEMC_VAL_USER_FLAGS_MAX) { + php_error_docref(NULL, E_WARNING, "MEMC_OPT_USER_FLAGS must be < %u", MEMC_VAL_USER_FLAGS_MAX); + return 0; + } + m_obj->set_udf_flags = Z_LVAL_P(value); + break; + case MEMC_OPT_STORE_RETRY_COUNT: convert_to_long(value); m_obj->store_retry_count = Z_LVAL_P(value); @@ -2805,23 +2810,23 @@ static void php_memc_destroy(struct memc_obj *m_obj, zend_bool persistent) if (m_obj->memc) { memcached_free(m_obj->memc); } - pefree(m_obj, persistent); } static void php_memc_free_storage(zend_object *obj) { php_memc_t *i_obj = php_memc_fetch_object(obj); - + if (i_obj->obj && !i_obj->is_persistent) { php_memc_destroy(i_obj->obj, 0); } + zval_ptr_dtor(&i_obj->last_udf_flags); zend_object_std_dtor(&i_obj->zo); i_obj->obj = NULL; } -zend_object *php_memc_new(zend_class_entry *ce) +static zend_object *php_memc_new(zend_class_entry *ce) { php_memc_t *i_obj = ecalloc(1, sizeof(php_memc_t) + zend_object_properties_size(ce)); @@ -3514,7 +3519,7 @@ static memcached_return php_memc_do_cache_callback(zval *zmemc_obj, zend_fcall_i fci->param_count = 4; result = zend_call_function(fci, fcc); - + ZVAL_DUP(value, Z_REFVAL(z_val)); expiration = Z_REFVAL(z_expiration); if (result == SUCCESS && Z_TYPE(retval) != IS_UNDEF) { @@ -3552,7 +3557,7 @@ static memcached_return php_memc_do_cache_callback(zval *zmemc_obj, zend_fcall_i ZVAL_NULL(value); } - if (&retval) { + if (!Z_ISUNDEF(retval)) { zval_ptr_dtor(&retval); } @@ -3712,7 +3717,6 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_get, 0, 0, 1) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, cache_cb) ZEND_ARG_INFO(2, cas_token) - ZEND_ARG_INFO(1, udf_flags) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_getByKey, 0, 0, 2) @@ -3720,14 +3724,12 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_getByKey, 0, 0, 2) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, cache_cb) ZEND_ARG_INFO(2, cas_token) - ZEND_ARG_INFO(1, udf_flags) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_getMulti, 0, 0, 1) ZEND_ARG_ARRAY_INFO(0, keys, 0) ZEND_ARG_INFO(2, cas_tokens) ZEND_ARG_INFO(0, flags) - ZEND_ARG_INFO(1, udf_flags) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_getMultiByKey, 0, 0, 2) @@ -3735,7 +3737,6 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_getMultiByKey, 0, 0, 2) ZEND_ARG_ARRAY_INFO(0, keys, 0) ZEND_ARG_INFO(2, cas_tokens) ZEND_ARG_INFO(0, flags) - ZEND_ARG_INFO(1, udf_flags) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_getDelayed, 0, 0, 1) @@ -3761,7 +3762,6 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_set, 0, 0, 2) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, value) ZEND_ARG_INFO(0, expiration) - ZEND_ARG_INFO(0, udf_flags) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_setByKey, 0, 0, 3) @@ -3769,7 +3769,6 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_setByKey, 0, 0, 3) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, value) ZEND_ARG_INFO(0, expiration) - ZEND_ARG_INFO(0, udf_flags) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_touch, 0, 0, 2) @@ -3786,21 +3785,21 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_setMulti, 0, 0, 1) ZEND_ARG_ARRAY_INFO(0, items, 0) ZEND_ARG_INFO(0, expiration) - ZEND_ARG_INFO(0, udf_flags) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_setMultiByKey, 0, 0, 2) ZEND_ARG_INFO(0, server_key) ZEND_ARG_ARRAY_INFO(0, items, 0) ZEND_ARG_INFO(0, expiration) - ZEND_ARG_INFO(0, udf_flags) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_getLastUserFlags, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_add, 0, 0, 2) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, value) ZEND_ARG_INFO(0, expiration) - ZEND_ARG_INFO(0, udf_flags) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_addByKey, 0, 0, 3) @@ -3808,14 +3807,12 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_addByKey, 0, 0, 3) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, value) ZEND_ARG_INFO(0, expiration) - ZEND_ARG_INFO(0, udf_flags) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_replace, 0, 0, 2) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, value) ZEND_ARG_INFO(0, expiration) - ZEND_ARG_INFO(0, udf_flags) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_replaceByKey, 0, 0, 3) @@ -3823,7 +3820,6 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_replaceByKey, 0, 0, 3) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, value) ZEND_ARG_INFO(0, expiration) - ZEND_ARG_INFO(0, udf_flags) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_append, 0, 0, 2) @@ -3857,7 +3853,6 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_cas, 0, 0, 3) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, value) ZEND_ARG_INFO(0, expiration) - ZEND_ARG_INFO(0, udf_flags) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_casByKey, 0, 0, 4) @@ -3866,7 +3861,6 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_casByKey, 0, 0, 4) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, value) ZEND_ARG_INFO(0, expiration) - ZEND_ARG_INFO(0, udf_flags) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_delete, 0, 0, 1) @@ -4029,6 +4023,8 @@ static zend_function_entry memcached_class_methods[] = { MEMC_ME(setMulti, arginfo_setMulti) MEMC_ME(setMultiByKey, arginfo_setMultiByKey) + MEMC_ME(getLastUserFlags, arginfo_getLastUserFlags) + MEMC_ME(cas, arginfo_cas) MEMC_ME(casByKey, arginfo_casByKey) MEMC_ME(add, arginfo_add) @@ -4187,6 +4183,8 @@ static void php_memc_register_constants(INIT_FUNC_ARGS) REGISTER_MEMC_CLASS_CONST_LONG(OPT_COMPRESSION_TYPE, MEMC_OPT_COMPRESSION_TYPE); REGISTER_MEMC_CLASS_CONST_LONG(OPT_PREFIX_KEY, MEMC_OPT_PREFIX_KEY); REGISTER_MEMC_CLASS_CONST_LONG(OPT_SERIALIZER, MEMC_OPT_SERIALIZER); + + REGISTER_MEMC_CLASS_CONST_LONG(OPT_USER_FLAGS, MEMC_OPT_USER_FLAGS); REGISTER_MEMC_CLASS_CONST_LONG(OPT_STORE_RETRY_COUNT, MEMC_OPT_STORE_RETRY_COUNT); /* diff --git a/tests/user-flags.phpt b/tests/user-flags.phpt index 2ed44c9a..137ff1e8 100644 --- a/tests/user-flags.phpt +++ b/tests/user-flags.phpt @@ -22,46 +22,78 @@ define ('FLAG_4', 4); define ('FLAG_32', 32); define ('FLAG_64', 64); define ('FLAG_TOO_LARGE', pow(2, 16)); -$x = 0; include dirname (__FILE__) . '/config.inc'; $m = memc_get_instance (array (Memcached::OPT_BINARY_PROTOCOL => true)); $key = uniqid ('udf_test_'); -echo "stored with flags" . PHP_EOL; +// Set with flags off +$m->set ($key, '1', 10); +$m->get($key); +var_dump($m->getLastUserFlags()); -$m->set ($key, '1', 10, FLAG_1 | FLAG_4 | FLAG_64); -$udf_flags = 0; -$value = $m->get ($key, null, $x, $udf_flags); +// Set flags on +$m->setOption(Memcached::OPT_USER_FLAGS, FLAG_1); +$m->set ($key, '1', 10); +$m->get($key); +check_flags($m->getLastUserFlags()[$key], array(FLAG_1)); -check_flags ($udf_flags, array (FLAG_1, FLAG_4, FLAG_64)); +// Multiple flags +$m->setOption(Memcached::OPT_USER_FLAGS, FLAG_1 | FLAG_2 | FLAG_4); +$m->set ($key, '1', 10); +$m->get($key); +check_flags($m->getLastUserFlags()[$key], array(FLAG_1, FLAG_2, FLAG_4)); -echo "stored without flags" . PHP_EOL; -$m->set ($key, '1'); -$value = $m->get ($key, null, $x, $udf_flags); +// Even more flags +$m->setOption(Memcached::OPT_USER_FLAGS, FLAG_1 | FLAG_2 | FLAG_4 | FLAG_32 | FLAG_64); +$m->set ($key, '1', 10); +$m->get($key); +check_flags($m->getLastUserFlags()[$key], array(FLAG_1, FLAG_2, FLAG_4, FLAG_32, FLAG_64)); -var_dump ($udf_flags == 0); -$m->set ($key, '1', 10, FLAG_TOO_LARGE); +// User flags with get multi +$values = array( + uniqid ('udf_test_multi_') => "first", + uniqid ('udf_test_multi_') => "second", + uniqid ('udf_test_multi_') => "third", +); +$m->setOption(Memcached::OPT_USER_FLAGS, FLAG_2 | FLAG_4); +$m->setMulti($values); +$m->getMulti(array_keys($values)); +$flags = $m->getLastUserFlags(); + +foreach (array_keys($values) as $key) { + check_flags($flags[$key], array(FLAG_2, FLAG_4)); +} + +// User flags with compression on +$m->setOption(Memcached::OPT_USER_FLAGS, FLAG_1 | FLAG_2 | FLAG_4); $m->setOption(Memcached::OPT_COMPRESSION, true); $m->setOption(Memcached::OPT_COMPRESSION_TYPE, Memcached::COMPRESSION_FASTLZ); -$m->set ($key, str_repeat ("abcdef1234567890", 200), 10, FLAG_1 | FLAG_4 | FLAG_64); +$m->set ($key, '1', 10); +$m->get($key); +check_flags($m->getLastUserFlags()[$key], array(FLAG_1, FLAG_2, FLAG_4)); -$udf_flags = 0; -$value_back = $m->get($key, null, null, $udf_flags); -check_flags ($udf_flags, array (FLAG_1, FLAG_4, FLAG_64)); +// Too large flags +$m->setOption(Memcached::OPT_USER_FLAGS, FLAG_TOO_LARGE); echo "DONE TEST\n"; ?> --EXPECTF-- -stored with flags +array(1) { + ["udf_test_%s"]=> + int(0) +} +Flags OK Flags OK -stored without flags -bool(true) - -Warning: Memcached::set(): udf_flags will be limited to 65535 in %s on line %d Flags OK +Flags OK +Flags OK +Flags OK +Flags OK + +Warning: Memcached::setOption(): MEMC_OPT_USER_FLAGS must be < 65535 in %s on line %d DONE TEST \ No newline at end of file From 9d5f3b956a7d0575c748cb2a4526171f63cee058 Mon Sep 17 00:00:00 2001 From: Mikko Date: Sat, 16 Jan 2016 21:53:07 +0000 Subject: [PATCH 035/104] Use cache with travis --- .travis.yml | 4 ++++ .travis/travis.sh | 28 +++++++++++++++++++++------- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 04f90cec..188bedba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,3 +24,7 @@ before_script: script: - ./.travis/travis.sh script $LIBMEMCACHED_VERSION + +cache: + directories: + - $HOME/cache \ No newline at end of file diff --git a/.travis/travis.sh b/.travis/travis.sh index e6733526..e87a372f 100755 --- a/.travis/travis.sh +++ b/.travis/travis.sh @@ -44,6 +44,12 @@ function validate_package_xml() { function install_libmemcached() { + if test -d "${LIBMEMCACHED_PREFIX}" + then + echo "Using cached libmemcached: ${LIBMEMCACHED_PREFIX}" + return + fi + wget "https://launchpad.net/libmemcached/1.0/${LIBMEMCACHED_VERSION}/+download/libmemcached-${LIBMEMCACHED_VERSION}.tar.gz" -O libmemcached-${LIBMEMCACHED_VERSION}.tar.gz tar xvfz libmemcached-${LIBMEMCACHED_VERSION}.tar.gz @@ -83,17 +89,25 @@ function install_msgpack() { function install_sasl() { - wget http://memcached.googlecode.com/files/memcached-1.4.15.tar.gz -O memcached-1.4.15.tar.gz - tar xfz memcached-1.4.15.tar.gz + local prefix="${HOME}/cache/memcached" + + if test -f "${prefix}/bin/memcached" + then + echo "Using cached memcached-sasl: ${prefix}/bin/memcached" + return + fi + + wget http://www.memcached.org/files/memcached-1.4.25.tar.gz -O memcached-1.4.25.tar.gz + tar xfz memcached-1.4.25.tar.gz - pushd memcached-1.4.15 - ./configure --enable-sasl --prefix="${HOME}/memcached" + pushd memcached-1.4.25 + ./configure --enable-sasl --prefix="${prefix}" make make install popd sudo apt-get install sasl2-bin - export SASL_CONF_PATH="${HOME}/sasl2" + export SASL_CONF_PATH="${HOME}/cache/sasl2" # Create config path mkdir "${SASL_CONF_PATH}" @@ -109,7 +123,7 @@ EOF echo "test" | /usr/sbin/saslpasswd2 -c memcached -a memcached -f "${SASL_CONF_PATH}/sasldb2" # Run memcached on port 11212 with SASL support - "${HOME}/memcached/bin/memcached" -S -d -p 11212 + "${prefix}/bin/memcached" -S -d -p 11212 } function build_php_memcached() { @@ -192,7 +206,7 @@ fi PHP_MEMCACHED_VERSION=$(php -r '$sxe = simplexml_load_file ("package.xml"); echo (string) $sxe->version->release;') # Libmemcached install dir -LIBMEMCACHED_PREFIX="${HOME}/libmemcached-${LIBMEMCACHED_VERSION}" +LIBMEMCACHED_PREFIX="${HOME}/cache/libmemcached-${LIBMEMCACHED_VERSION}" # Where to do the build PHP_MEMCACHED_BUILD_DIR="/tmp/php-memcached-build" From 852d60cbc726532310abf598c6ea391b0c6407c4 Mon Sep 17 00:00:00 2001 From: Mikko Date: Sat, 16 Jan 2016 22:00:30 +0000 Subject: [PATCH 036/104] More travis updates --- .travis.yml | 11 ++++++++++- .travis/travis.sh | 1 - 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 188bedba..c60ed89c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,11 @@ env: - LIBMEMCACHED_VERSION=0.53 - LIBMEMCACHED_VERSION=0.49 - LIBMEMCACHED_VERSION=0.44 +addons: + apt: + packages: + - sasl2-bin + - libsasl2-dev services: - memcached # will start memcached @@ -25,6 +30,10 @@ before_script: script: - ./.travis/travis.sh script $LIBMEMCACHED_VERSION +sudo: false + cache: directories: - - $HOME/cache \ No newline at end of file + - $HOME/cache + + \ No newline at end of file diff --git a/.travis/travis.sh b/.travis/travis.sh index e87a372f..923eb518 100755 --- a/.travis/travis.sh +++ b/.travis/travis.sh @@ -106,7 +106,6 @@ function install_sasl() { make install popd - sudo apt-get install sasl2-bin export SASL_CONF_PATH="${HOME}/cache/sasl2" # Create config path From f3bfce3ec85e7aa8a25a28de1bc04bb0263df993 Mon Sep 17 00:00:00 2001 From: Mikko Date: Sat, 16 Jan 2016 22:17:21 +0000 Subject: [PATCH 037/104] Run our own memcached --- .travis.yml | 4 +--- .travis/travis.sh | 40 ++++++++++++++++++++++++++++------------ 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index c60ed89c..30e5c3e1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ php: - 7.0 env: + - LIBMEMCACHED_VERSION=1.0.18 - LIBMEMCACHED_VERSION=1.0.17 - LIBMEMCACHED_VERSION=1.0.16 - LIBMEMCACHED_VERSION=1.0.15 @@ -21,9 +22,6 @@ addons: - sasl2-bin - libsasl2-dev -services: - - memcached # will start memcached - before_script: - ./.travis/travis.sh before_script $LIBMEMCACHED_VERSION diff --git a/.travis/travis.sh b/.travis/travis.sh index 923eb518..a80e0cf3 100755 --- a/.travis/travis.sh +++ b/.travis/travis.sh @@ -1,5 +1,7 @@ #!/bin/bash +MEMCACHED_VERSION="1.4.25" + function version_compare() { DPKG=`which dpkg` @@ -87,27 +89,35 @@ function install_msgpack() { popd } -function install_sasl() { - +function install_memcached() { local prefix="${HOME}/cache/memcached" - if test -f "${prefix}/bin/memcached" + if test -d "$prefix" then - echo "Using cached memcached-sasl: ${prefix}/bin/memcached" + echo "Using cached memcached: ${prefix}" return fi - wget http://www.memcached.org/files/memcached-1.4.25.tar.gz -O memcached-1.4.25.tar.gz - tar xfz memcached-1.4.25.tar.gz + wget http://www.memcached.org/files/memcached-${MEMCACHED_VERSION}.tar.gz -O memcached-${MEMCACHED_VERSION}.tar.gz + tar xfz memcached-${MEMCACHED_VERSION}.tar.gz - pushd memcached-1.4.25 + pushd memcached-${MEMCACHED_VERSION} ./configure --enable-sasl --prefix="${prefix}" make make install popd +} + +function install_sasl_config() { export SASL_CONF_PATH="${HOME}/cache/sasl2" + if test -f "${SASL_CONF_PATH}/memcached.conf" + then + echo "Using cached SASL configuration: ${SASL_CONF_PATH}/memcached.conf" + return + fi + # Create config path mkdir "${SASL_CONF_PATH}" @@ -120,6 +130,13 @@ EOF # Create password echo "test" | /usr/sbin/saslpasswd2 -c memcached -a memcached -f "${SASL_CONF_PATH}/sasldb2" +} + +function run_memcached() { + local prefix="${HOME}/cache/memcached" + + # Run normal memcached + "${prefix}/bin/memcached" -d -p 11211 # Run memcached on port 11212 with SASL support "${prefix}/bin/memcached" -S -d -p 11212 @@ -232,11 +249,10 @@ case $ACTION in # install msgpack # install_msgpack - - # install SASL - if test "x$ENABLE_SASL" = "xyes"; then - install_sasl - fi + + install_memcached + install_sasl_config + run_memcached ;; script) From dcdd3b88c57f6ee2fc43d20f1ec7ad7444c42be5 Mon Sep 17 00:00:00 2001 From: Mikko Date: Sat, 16 Jan 2016 22:22:25 +0000 Subject: [PATCH 038/104] Allow specifying memcached version --- .travis/travis.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.travis/travis.sh b/.travis/travis.sh index a80e0cf3..78ae9ffb 100755 --- a/.travis/travis.sh +++ b/.travis/travis.sh @@ -1,7 +1,5 @@ #!/bin/bash -MEMCACHED_VERSION="1.4.25" - function version_compare() { DPKG=`which dpkg` @@ -90,7 +88,7 @@ function install_msgpack() { } function install_memcached() { - local prefix="${HOME}/cache/memcached" + local prefix="${HOME}/cache/memcached-${MEMCACHED_VERSION}" if test -d "$prefix" then @@ -133,7 +131,7 @@ EOF } function run_memcached() { - local prefix="${HOME}/cache/memcached" + local prefix="${HOME}/cache/memcached-${MEMCACHED_VERSION}" # Run normal memcached "${prefix}/bin/memcached" -d -p 11211 @@ -207,6 +205,7 @@ function run_memcached_tests() { # Command line arguments ACTION=$1 LIBMEMCACHED_VERSION=$2 +MEMCACHED_VERSION="1.4.25" if test "x$ACTION" = "x"; then echo "Usage: $0 " @@ -218,6 +217,10 @@ if test "x$LIBMEMCACHED_VERSION" = "x"; then exit 1 fi +if test "x$3" != "x"; then + MEMCACHED_VERSION=$3 +fi + # the extension version PHP_MEMCACHED_VERSION=$(php -r '$sxe = simplexml_load_file ("package.xml"); echo (string) $sxe->version->release;') From 5eb3bfd4fe8a6532ad80fc784020e70fabfedfec Mon Sep 17 00:00:00 2001 From: Mikko Date: Mon, 18 Jan 2016 04:05:32 +0000 Subject: [PATCH 039/104] Fixes to keys and tests --- php_memcached.c | 14 +++++++------- tests/keys.phpt | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index c7fb08ba..f5a9ea22 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -424,6 +424,7 @@ static PHP_METHOD(Memcached, __construct) } i_obj->is_persistent = is_persistent; + array_init(&i_obj->last_udf_flags); if (!m_obj) { m_obj = pecalloc(1, sizeof(*m_obj), is_persistent); @@ -470,7 +471,6 @@ static PHP_METHOD(Memcached, __construct) m_obj->store_retry_count = MEMC_G(store_retry_count); m_obj->set_udf_flags = -1; - array_init(&i_obj->last_udf_flags); i_obj->obj = m_obj; i_obj->is_pristine = 1; @@ -580,7 +580,7 @@ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) zend_hash_clean(Z_ARRVAL(i_obj->last_udf_flags)); - if (key->len == 0) { + if (key->len == 0 || (!memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) && strchr(key->val, ' '))) { i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; RETURN_FROM_GET; } @@ -1423,7 +1423,7 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool MEMC_METHOD_FETCH_OBJECT; i_obj->rescode = MEMCACHED_SUCCESS; - if (key->len == 0) { + if (key->len == 0 || (!memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) && strchr(key->val, ' '))) { i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; RETURN_FALSE; } @@ -1568,7 +1568,7 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) MEMC_METHOD_FETCH_OBJECT; i_obj->rescode = MEMCACHED_SUCCESS; - if (key->len == 0) { + if (key->len == 0 || (!memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) && strchr(key->val, ' '))) { i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; RETURN_FALSE; } @@ -1677,7 +1677,7 @@ static void php_memc_delete_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) MEMC_METHOD_FETCH_OBJECT; i_obj->rescode = MEMCACHED_SUCCESS; - if (key->len == 0 || strchr(key->val, ' ')) { + if (key->len == 0 || (!memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) && strchr(key->val, ' '))) { i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; RETURN_FALSE; } @@ -1775,7 +1775,7 @@ static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key, MEMC_METHOD_FETCH_OBJECT; i_obj->rescode = MEMCACHED_SUCCESS; - if (key->len == 0 || strchr(key->val, ' ')) { + if (key->len == 0 || (!memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) && strchr(key->val, ' '))) { i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; RETURN_FALSE; } @@ -2020,7 +2020,7 @@ PHP_METHOD(Memcached, getServerByKey) MEMC_METHOD_FETCH_OBJECT; i_obj->rescode = MEMCACHED_SUCCESS; - if (server_key->len == 0 || strchr(server_key->val, ' ')) { + if (server_key->len == 0 || (!memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) && strchr(server_key->val, ' '))) { i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; RETURN_FALSE; } diff --git a/tests/keys.phpt b/tests/keys.phpt index 0ed90896..89632f5d 100644 --- a/tests/keys.phpt +++ b/tests/keys.phpt @@ -13,7 +13,7 @@ $binary = memc_get_instance (array ( $ascii = memc_get_instance (); var_dump ($binary->set ('binary key with spaces', 'this is a test')); -var_dump ($binary->getResultCode () == Memcached::RES_BAD_KEY_PROVIDED); +var_dump ($binary->getResultCode () == Memcached::RES_SUCCESS); var_dump ($ascii->set ('ascii key with spaces', 'this is a test')); var_dump ($ascii->getResultCode () == Memcached::RES_BAD_KEY_PROVIDED); @@ -24,7 +24,7 @@ var_dump ($ascii->getResultCode () == Memcached::RES_BAD_KEY_PROVIDED); echo "OK" . PHP_EOL; --EXPECT-- -bool(false) +bool(true) bool(true) bool(false) bool(true) From 029784c6870fcd812e58f56c4a17a51e198eb2fc Mon Sep 17 00:00:00 2001 From: Mikko Date: Mon, 18 Jan 2016 04:17:19 +0000 Subject: [PATCH 040/104] Show diff --- .travis/travis.sh | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/.travis/travis.sh b/.travis/travis.sh index 78ae9ffb..a80ca77a 100755 --- a/.travis/travis.sh +++ b/.travis/travis.sh @@ -181,7 +181,7 @@ EOF function run_memcached_tests() { export NO_INTERACTION=1 export REPORT_EXIT_STATUS=1 - export TEST_PHP_EXECUTABLE=`which php` + export TEST_PHP_EXECUTABLE=$(which php) pushd "${PHP_MEMCACHED_BUILD_DIR}/memcached-${PHP_MEMCACHED_VERSION}" # We have one xfail test, we run it separately @@ -189,14 +189,8 @@ function run_memcached_tests() { rm ./tests/expire.phpt # Run normal tests - php run-tests.php -d extension=memcached.so -n ./tests/*.phpt + php run-tests.php --show-diff -d extension=memcached.so -n ./tests/*.phpt retval=$? - for i in `ls tests/*.out 2>/dev/null`; do - echo "-- START ${i}"; - cat $i; - echo ""; - echo "-- END"; - done popd return $retval; From 00d99deb90d8bcd667f7ea2d008218d8e82ab601 Mon Sep 17 00:00:00 2001 From: Mikko Date: Mon, 18 Jan 2016 04:42:16 +0000 Subject: [PATCH 041/104] Should fix sasl --- .travis/travis.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis/travis.sh b/.travis/travis.sh index a80ca77a..b2ef1fb7 100755 --- a/.travis/travis.sh +++ b/.travis/travis.sh @@ -137,7 +137,7 @@ function run_memcached() { "${prefix}/bin/memcached" -d -p 11211 # Run memcached on port 11212 with SASL support - "${prefix}/bin/memcached" -S -d -p 11212 + MEMCACHED_SASL_PWDB="${SASL_CONF_PATH}/sasldb2" "${prefix}/bin/memcached" -S -d -p 11212 } function build_php_memcached() { From 238a403ea87036c18982dfcb1d7d3fea26cb367b Mon Sep 17 00:00:00 2001 From: Mikko Date: Mon, 18 Jan 2016 04:45:59 +0000 Subject: [PATCH 042/104] Should fix sasl --- .travis/travis.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis/travis.sh b/.travis/travis.sh index b2ef1fb7..d841a4b3 100755 --- a/.travis/travis.sh +++ b/.travis/travis.sh @@ -88,7 +88,7 @@ function install_msgpack() { } function install_memcached() { - local prefix="${HOME}/cache/memcached-${MEMCACHED_VERSION}" + local prefix="${HOME}/cache/memcached-sasl-${MEMCACHED_VERSION}" if test -d "$prefix" then @@ -100,7 +100,7 @@ function install_memcached() { tar xfz memcached-${MEMCACHED_VERSION}.tar.gz pushd memcached-${MEMCACHED_VERSION} - ./configure --enable-sasl --prefix="${prefix}" + ./configure --enable-sasl --enable-sasl-pwdb --prefix="${prefix}" make make install popd @@ -137,7 +137,8 @@ function run_memcached() { "${prefix}/bin/memcached" -d -p 11211 # Run memcached on port 11212 with SASL support - MEMCACHED_SASL_PWDB="${SASL_CONF_PATH}/sasldb2" "${prefix}/bin/memcached" -S -d -p 11212 + export MEMCACHED_SASL_PWDB="${SASL_CONF_PATH}/sasldb2" + "${prefix}/bin/memcached" -S -d -p 11212 } function build_php_memcached() { From 5a1d092b7fafbb80bc3e6eb47ead104b10ae1ad6 Mon Sep 17 00:00:00 2001 From: Mikko Date: Mon, 18 Jan 2016 04:49:03 +0000 Subject: [PATCH 043/104] Run right memcached --- .travis/travis.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis/travis.sh b/.travis/travis.sh index d841a4b3..3d2af8ae 100755 --- a/.travis/travis.sh +++ b/.travis/travis.sh @@ -131,7 +131,7 @@ EOF } function run_memcached() { - local prefix="${HOME}/cache/memcached-${MEMCACHED_VERSION}" + local prefix="${HOME}/cache/memcached-sasl-${MEMCACHED_VERSION}" # Run normal memcached "${prefix}/bin/memcached" -d -p 11211 From 37f261879742d52a329e9c172ef2cce6f1a34684 Mon Sep 17 00:00:00 2001 From: Mikko Date: Mon, 18 Jan 2016 05:00:55 +0000 Subject: [PATCH 044/104] Memcached log --- .travis/travis.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis/travis.sh b/.travis/travis.sh index 3d2af8ae..96f6bc31 100755 --- a/.travis/travis.sh +++ b/.travis/travis.sh @@ -137,8 +137,11 @@ function run_memcached() { "${prefix}/bin/memcached" -d -p 11211 # Run memcached on port 11212 with SASL support + echo "SASL users:" + sasldblistusers2 -f "${SASL_CONF_PATH}/sasldb2" + export MEMCACHED_SASL_PWDB="${SASL_CONF_PATH}/sasldb2" - "${prefix}/bin/memcached" -S -d -p 11212 + "${prefix}/bin/memcached" -S -d -v -p 11212 > /tmp/memcached-sasl.log 2>&1 } function build_php_memcached() { @@ -194,6 +197,7 @@ function run_memcached_tests() { retval=$? popd + cat /tmp/memcached-sasl.log return $retval; } From 7e5f0922420ce5d4d472dcafd3e9569eec92fb8b Mon Sep 17 00:00:00 2001 From: Mikko Date: Mon, 18 Jan 2016 05:26:00 +0000 Subject: [PATCH 045/104] SASL is tricky --- .travis/travis.sh | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/.travis/travis.sh b/.travis/travis.sh index 96f6bc31..3924efd6 100755 --- a/.travis/travis.sh +++ b/.travis/travis.sh @@ -106,41 +106,32 @@ function install_memcached() { popd } -function install_sasl_config() { +function run_memcached() { + local prefix="${HOME}/cache/memcached-sasl-${MEMCACHED_VERSION}" - export SASL_CONF_PATH="${HOME}/cache/sasl2" + export SASL_CONF_PATH="/tmp/sasl2" - if test -f "${SASL_CONF_PATH}/memcached.conf" + if test -d "${SASL_CONF_PATH}" then - echo "Using cached SASL configuration: ${SASL_CONF_PATH}/memcached.conf" - return + rm -rf "${SASL_CONF_PATH}" fi - # Create config path mkdir "${SASL_CONF_PATH}" + export MEMCACHED_SASL_PWDB="${SASL_CONF_PATH}/sasldb2" # Create configuration cat< "${SASL_CONF_PATH}/memcached.conf" mech_list: PLAIN plainlog_level: 5 -sasldb_path: ${SASL_CONF_PATH}/sasldb2 +sasldb_path: ${MEMCACHED_SASL_PWDB} EOF - # Create password - echo "test" | /usr/sbin/saslpasswd2 -c memcached -a memcached -f "${SASL_CONF_PATH}/sasldb2" -} - -function run_memcached() { - local prefix="${HOME}/cache/memcached-sasl-${MEMCACHED_VERSION}" + echo "test" | /usr/sbin/saslpasswd2 -c memcached -a memcached -f "${MEMCACHED_SASL_PWDB}" # Run normal memcached "${prefix}/bin/memcached" -d -p 11211 # Run memcached on port 11212 with SASL support - echo "SASL users:" - sasldblistusers2 -f "${SASL_CONF_PATH}/sasldb2" - - export MEMCACHED_SASL_PWDB="${SASL_CONF_PATH}/sasldb2" "${prefix}/bin/memcached" -S -d -v -p 11212 > /tmp/memcached-sasl.log 2>&1 } @@ -253,7 +244,6 @@ case $ACTION in # install_msgpack install_memcached - install_sasl_config run_memcached ;; From 1aab3f70f7c6a8cac480e1244b7eafbb75bc9c40 Mon Sep 17 00:00:00 2001 From: Mikko Date: Mon, 18 Jan 2016 05:28:33 +0000 Subject: [PATCH 046/104] Remove debug logging --- .travis/travis.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis/travis.sh b/.travis/travis.sh index 3924efd6..a6240d83 100755 --- a/.travis/travis.sh +++ b/.travis/travis.sh @@ -132,7 +132,7 @@ EOF "${prefix}/bin/memcached" -d -p 11211 # Run memcached on port 11212 with SASL support - "${prefix}/bin/memcached" -S -d -v -p 11212 > /tmp/memcached-sasl.log 2>&1 + "${prefix}/bin/memcached" -S -d -v -p 11212 } function build_php_memcached() { @@ -187,8 +187,6 @@ function run_memcached_tests() { php run-tests.php --show-diff -d extension=memcached.so -n ./tests/*.phpt retval=$? popd - - cat /tmp/memcached-sasl.log return $retval; } From e6946ee636b6db6dae60b0c9067a9def42b4cbbc Mon Sep 17 00:00:00 2001 From: Mikko Date: Mon, 18 Jan 2016 05:30:26 +0000 Subject: [PATCH 047/104] Remove debug logging --- .travis/travis.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis/travis.sh b/.travis/travis.sh index a6240d83..131e38bf 100755 --- a/.travis/travis.sh +++ b/.travis/travis.sh @@ -132,7 +132,7 @@ EOF "${prefix}/bin/memcached" -d -p 11211 # Run memcached on port 11212 with SASL support - "${prefix}/bin/memcached" -S -d -v -p 11212 + "${prefix}/bin/memcached" -S -d -p 11212 } function build_php_memcached() { From fd8fead6bd02f5aa28ac622b45dd2642763507af Mon Sep 17 00:00:00 2001 From: Mikko Date: Mon, 18 Jan 2016 05:41:18 +0000 Subject: [PATCH 048/104] Remove really old libmemcached versions. If anyone is using this old version they should be worried --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 30e5c3e1..fb0d0fbe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,9 +13,9 @@ env: - LIBMEMCACHED_VERSION=1.0.7 - LIBMEMCACHED_VERSION=1.0.6 - LIBMEMCACHED_VERSION=1.0.2 - - LIBMEMCACHED_VERSION=0.53 - - LIBMEMCACHED_VERSION=0.49 - - LIBMEMCACHED_VERSION=0.44 + #- LIBMEMCACHED_VERSION=0.53 + #- LIBMEMCACHED_VERSION=0.49 + #- LIBMEMCACHED_VERSION=0.44 addons: apt: packages: From 582f4a030d15832475ea5baa70d2e92e298ec3c1 Mon Sep 17 00:00:00 2001 From: Mikko Date: Thu, 21 Jan 2016 00:02:11 +0000 Subject: [PATCH 049/104] Fix tests --- tests/session_basic2.phpt | 2 +- tests/session_basic3.phpt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/session_basic2.phpt b/tests/session_basic2.phpt index f99063a8..6ec4060e 100644 --- a/tests/session_basic2.phpt +++ b/tests/session_basic2.phpt @@ -18,7 +18,7 @@ ini_set ('session.save_path', MEMC_SERVER_HOST . ':' . MEMC_SERVER_PORT); error_reporting(0); -session_start(['lazy_write'=>TRUE); +session_start(['lazy_write'=>TRUE]); $_SESSION['foo'] = 1; session_write_close(); diff --git a/tests/session_basic3.phpt b/tests/session_basic3.phpt index fc4e7ae7..b8e4f5f8 100644 --- a/tests/session_basic3.phpt +++ b/tests/session_basic3.phpt @@ -18,7 +18,7 @@ ini_set ('session.save_path', MEMC_SERVER_HOST . ':' . MEMC_SERVER_PORT); error_reporting(0); -session_start(['read_only'=>TRUE); +session_start(['read_only'=>TRUE]); $_SESSION['foo'] = 1; session_write_close(); From 7ac4e83c6cf4aa8e16f8088534096293ee8e254d Mon Sep 17 00:00:00 2001 From: Mikko Date: Thu, 21 Jan 2016 00:32:09 +0000 Subject: [PATCH 050/104] Add to package.xml --- package.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/package.xml b/package.xml index 0ebc86f9..e42b8037 100644 --- a/package.xml +++ b/package.xml @@ -100,6 +100,8 @@ http://pear.php.net/dtd/package-2.0.xsd"> + + From 7cb0c48c8da8fbcfdd04350338d6ebef15ddcd14 Mon Sep 17 00:00:00 2001 From: Mikko Date: Thu, 21 Jan 2016 13:42:17 +0000 Subject: [PATCH 051/104] Fixes to session --- config.m4 | 22 +++++++++++++++++++++ php_memcached.c | 19 +++++++++++++++++++ php_memcached_private.h | 2 ++ php_memcached_session.c | 42 +++++++++++++++++++---------------------- 4 files changed, 62 insertions(+), 23 deletions(-) diff --git a/config.m4 b/config.m4 index 48efd176..e6a2dfd0 100644 --- a/config.m4 +++ b/config.m4 @@ -296,6 +296,28 @@ if test "$PHP_MEMCACHED" != "no"; then AC_MSG_RESULT([no]) fi + ORIG_CFLAGS="$CFLAGS" + ORIG_LIBS="$LIBS" + + CFLAGS="$CFLAGS $PHP_LIBMEMCACHED_INCLUDES" + LIBS="$LIBS $PHP_LIBMEMCACHED_LIBS" + + AC_CACHE_CHECK([whether memcached_exist is defined], ac_cv_have_memcached_exist, [ + AC_TRY_LINK( + [ #include ], + [ memcached_exist (NULL, NULL, 0); ], + [ ac_cv_have_memcached_exist="yes" ], + [ ac_cv_have_memcached_exist="no" ] + ) + ]) + + CFLAGS="$ORIG_CFLAGS" + LIBS="$ORIG_LIBS" + + if test "$ac_cv_have_memcached_exist" = "yes"; then + AC_DEFINE(HAVE_MEMCACHED_EXIST, [1], [Whether memcached_exist is defined]) + fi + PHP_MEMCACHED_FILES="php_memcached.c php_libmemcached_compat.c g_fmt.c" if test "$PHP_SYSTEM_FASTLZ" != "no"; then diff --git a/php_memcached.c b/php_memcached.c index f5a9ea22..6f4ae3b1 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -332,6 +332,25 @@ static void php_memc_destroy(struct memc_obj *m_obj, zend_bool persistent); ****************************************/ +memcached_return php_memcached_exist (memcached_st *memc, zend_string *key) +{ +#ifdef HAVE_MEMCACHED_EXIST + return memcached_exist (memc, key->val, key->len); +#else + memcached_return rc = MEMCACHED_SUCCESS; + uint32_t flags = 0; + size_t value_length = 0; + char *value = NULL; + + value = memcached_get (memc, key->val, key->len, &value_length, &flags, &rc); + if (value) { + free (value); + } + return rc; +#endif +} + + char *php_memc_printable_func (zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) { char *buffer = NULL; diff --git a/php_memcached_private.h b/php_memcached_private.h index 2929818e..ffca963d 100644 --- a/php_memcached_private.h +++ b/php_memcached_private.h @@ -192,6 +192,8 @@ int php_memc_sess_list_entry(void); char *php_memc_printable_func (zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TSRMLS_DC); +memcached_return php_memcached_exist (memcached_st *memc, zend_string *key); + #endif /* PHP_MEMCACHED_PRIVATE_H */ /* diff --git a/php_memcached_session.c b/php_memcached_session.c index 5f66e411..85baad03 100644 --- a/php_memcached_session.c +++ b/php_memcached_session.c @@ -277,7 +277,7 @@ PS_OPEN_FUNC(memcached) PS_CLOSE_FUNC(memcached) { memcached_sess *memc_sess = PS_GET_MOD_DATA(); - + if (!memc_sess) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session is not allocated, check session.save_path value"); return FAILURE; @@ -336,8 +336,9 @@ PS_READ_FUNC(memcached) *val = zend_string_init(payload, payload_len, 1); free(payload); return SUCCESS; - } else if (status = MEMCACHED_NOTFOUND) { + } else if (status == MEMCACHED_NOTFOUND) { *val = ZSTR_EMPTY_ALLOC(); + return SUCCESS; } else { return FAILURE; } @@ -351,7 +352,7 @@ PS_WRITE_FUNC(memcached) memcached_return status; memcached_sess *memc_sess = PS_GET_MOD_DATA(); size_t key_length; - + if (!memc_sess) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session is not allocated, check session.save_path value"); return FAILURE; @@ -409,39 +410,34 @@ PS_GC_FUNC(memcached) PS_CREATE_SID_FUNC(memcached) { zend_string *sid; - int maxfail = 3; + int retries = 3; memcached_sess *memc_sess = PS_GET_MOD_DATA(); + time_t expiration = PS(gc_maxlifetime); - do { + if (!memc_sess) { + return NULL; + } + + while (retries-- > 0) { sid = php_session_create_id((void**)&memc_sess); - if (!sid) { - if (--maxfail < 0) { - return NULL; - } else { - continue; + + if (sid) { + if (memcached_add(memc_sess->memc_sess, sid->val, sid->len, "0", 0, expiration, 0) == MEMCACHED_SUCCESS) { + return sid; } - } - /* Check collision */ - /* FIXME: mod_data(memc_sess) should not be NULL (User handler could be NULL) */ - if (memc_sess && memcached_exist(memc_sess->memc_sess, sid->val, sid->len) == MEMCACHED_SUCCESS) { - if (sid) { + else { zend_string_release(sid); - sid = NULL; - } - if (--maxfail < 0) { - return NULL; } } - } while(!sid); - - return sid; + } + return NULL; } PS_VALIDATE_SID_FUNC(memcached) { memcached_sess *memc_sess = PS_GET_MOD_DATA(); - if (memcached_exist(memc_sess->memc_sess, key->val, key->len) == MEMCACHED_SUCCESS) { + if (php_memcached_exist(memc_sess->memc_sess, key) == MEMCACHED_SUCCESS) { return SUCCESS; } else { return FAILURE; From dc5b22a8dace7373c1ef9d2946e89a660ed35b20 Mon Sep 17 00:00:00 2001 From: Mikko Date: Fri, 29 Jan 2016 14:58:50 +0000 Subject: [PATCH 052/104] Cleaning up driver for php7. WIP --- php_memcached.c | 1141 ++++++++++++++++++-------------------- php_memcached_private.h | 83 +-- php_memcached_session.c | 628 +++++++++++---------- php_memcached_session.h | 3 + tests/cachecallback.phpt | 4 + tests/cas.phpt | 43 +- tests/cas_multi.phpt | 31 +- tests/multi_order.phpt | 3 +- tests/no-not-found.phpt | 3 +- tests/rescode.phpt | 1 + tests/set_large.phpt | 3 +- tests/user-flags.phpt | 28 +- 12 files changed, 967 insertions(+), 1004 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index 6f4ae3b1..23e9bde3 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -49,6 +49,12 @@ # include "ext/msgpack/php_msgpack.h" #endif +#ifdef ZTS +#define MEMC_G(v) TSRMG(php_memcached_globals_id, zend_php_memcached_globals *, memc_ini.v) +#else +#define MEMC_G(v) (php_memcached_globals.memc_ini.v) +#endif + /**************************************** Custom options @@ -106,7 +112,7 @@ "get" operation flags ****************************************/ #define MEMC_GET_PRESERVE_ORDER (1<<0) - +#define MEMC_GET_EXTENDED (2<<0) /**************************************** Helper macros @@ -136,6 +142,47 @@ #define RETURN_FROM_GET RETURN_FALSE +typedef memcached_return (*memc_store_fn)( + memcached_st *, + const char *key, size_t key_len, + const char *payload, size_t payload_len, + time_t expiration, uint32_t flags); + +typedef memcached_return (*memc_store_by_key_fn)( + memcached_st *, + const char *server_key, size_t server_key_len, + const char *key, size_t key_len, + const char *payload, size_t payload_len, + time_t expiration, uint32_t flags); + +static memc_store_fn php_memc_store_funcs[] = { + &memcached_set, + &memcached_add, + &memcached_replace, + &memcached_prepend, + &memcached_append +}; + +void s_call_store_func(int op, memcached_st *memc, const char *key, size_t key_len, const char *payload, size_t payload_len, time_t expiration, uint32_t flags) +{ + (*php_memc_store_funcs[op])(memc, key, key_len,payload, payload_len, expiration, flags); +} + + +static memc_store_by_key_fn php_memc_store_by_keys_funcs[] = { + &memcached_set_by_key, + &memcached_add_by_key, + &memcached_replace_by_key, + &memcached_prepend_by_key, + &memcached_append_by_key +}; + +void s_call_store_by_key_func(int op, memcached_st *memc, const char *server_key, size_t server_key_len, const char *key, size_t key_len, const char *payload, size_t payload_len, time_t expiration, uint32_t flags) +{ + (*php_memc_store_by_keys_funcs[op])(memc, server_key, server_key_len, key, key_len,payload, payload_len, expiration, flags); +} + + /**************************************** Structures and definitions ****************************************/ @@ -157,7 +204,6 @@ typedef struct { zend_long set_udf_flags; } *obj; - zval last_udf_flags; zend_bool is_persistent; zend_bool is_pristine; int rescode; @@ -220,14 +266,6 @@ struct callbackContext static zend_class_entry *spl_ce_RuntimeException = NULL; #endif -#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 3) -const zend_fcall_info empty_fcall_info = { 0, NULL, NULL, NULL, NULL, 0, NULL, NULL, 0 }; -#undef ZEND_BEGIN_ARG_INFO_EX -#define ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, return_reference, required_num_args) \ - static zend_arg_info name[] = { \ - { NULL, 0, NULL, 0, 0, 0, pass_rest_by_reference, return_reference, required_num_args }, -#endif - ZEND_DECLARE_MODULE_GLOBALS(php_memcached) #ifdef COMPILE_DL_MEMCACHED @@ -275,44 +313,54 @@ static PHP_INI_MH(OnUpdateSerializer) return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); } +#define MEMC_INI_ENTRY(key, default_value, update_fn, gkey) \ + STD_PHP_INI_ENTRY("memcached.##key", default_value, PHP_INI_ALL, update_fn, memc_ini.gkey, zend_php_memcached_globals, php_memcached_globals) + +#define MEMC_SESSION_INI_ENTRY(key, default_value, update_fn, gkey) \ + STD_PHP_INI_ENTRY("memcached.session.##key", default_value, PHP_INI_ALL, update_fn, session_ini.gkey, zend_php_memcached_globals, php_memcached_globals) + + /* {{{ INI entries */ PHP_INI_BEGIN() + #ifdef HAVE_MEMCACHED_SESSION - STD_PHP_INI_ENTRY("memcached.sess_locking", "1", PHP_INI_ALL, OnUpdateBool, sess_locking_enabled, zend_php_memcached_globals, php_memcached_globals) - STD_PHP_INI_ENTRY("memcached.sess_consistent_hash", "0", PHP_INI_ALL, OnUpdateBool, sess_consistent_hash_enabled, zend_php_memcached_globals, php_memcached_globals) - STD_PHP_INI_ENTRY("memcached.sess_binary", "0", PHP_INI_ALL, OnUpdateBool, sess_binary_enabled, zend_php_memcached_globals, php_memcached_globals) - STD_PHP_INI_ENTRY("memcached.sess_lock_wait", "150000", PHP_INI_ALL, OnUpdateLongGEZero,sess_lock_wait, zend_php_memcached_globals, php_memcached_globals) - STD_PHP_INI_ENTRY("memcached.sess_lock_max_wait", "0", PHP_INI_ALL, OnUpdateLongGEZero, sess_lock_max_wait, zend_php_memcached_globals, php_memcached_globals) - STD_PHP_INI_ENTRY("memcached.sess_lock_expire", "0", PHP_INI_ALL, OnUpdateLongGEZero, sess_lock_expire, zend_php_memcached_globals, php_memcached_globals) - STD_PHP_INI_ENTRY("memcached.sess_prefix", "memc.sess.key.", PHP_INI_ALL, OnUpdateString, sess_prefix, zend_php_memcached_globals, php_memcached_globals) - - STD_PHP_INI_ENTRY("memcached.sess_number_of_replicas", "0", PHP_INI_ALL, OnUpdateLongGEZero, sess_number_of_replicas, zend_php_memcached_globals, php_memcached_globals) - STD_PHP_INI_ENTRY("memcached.sess_randomize_replica_read", "0", PHP_INI_ALL, OnUpdateBool, sess_randomize_replica_read, zend_php_memcached_globals, php_memcached_globals) - STD_PHP_INI_ENTRY("memcached.sess_remove_failed", "0", PHP_INI_ALL, OnUpdateBool, sess_remove_failed_enabled, zend_php_memcached_globals, php_memcached_globals) - STD_PHP_INI_ENTRY("memcached.sess_connect_timeout", "1000", PHP_INI_ALL, OnUpdateLong, sess_connect_timeout, zend_php_memcached_globals, php_memcached_globals) -#if HAVE_MEMCACHED_SASL - STD_PHP_INI_ENTRY("memcached.sess_sasl_username", "", PHP_INI_ALL, OnUpdateString, sess_sasl_username, zend_php_memcached_globals, php_memcached_globals) - STD_PHP_INI_ENTRY("memcached.sess_sasl_password", "", PHP_INI_ALL, OnUpdateString, sess_sasl_password, zend_php_memcached_globals, php_memcached_globals) + MEMC_SESSION_INI_ENTRY("lock_enabled", "1", OnUpdateBool, lock_enabled) + MEMC_SESSION_INI_ENTRY("lock_wait_min", "1000", OnUpdateLongGEZero, lock_wait_min) + MEMC_SESSION_INI_ENTRY("lock_wait_max", "2000", OnUpdateLongGEZero, lock_wait_max) + MEMC_SESSION_INI_ENTRY("lock_retries", "5", OnUpdateLongGEZero, lock_retries) + MEMC_SESSION_INI_ENTRY("lock_expiration", "0", OnUpdateLongGEZero, lock_expiration) + MEMC_SESSION_INI_ENTRY("compression", "1", OnUpdateBool, compression_enabled) + MEMC_SESSION_INI_ENTRY("binary_protocol", "1", OnUpdateBool, binary_protocol_enabled) + MEMC_SESSION_INI_ENTRY("consistent_hash", "1", OnUpdateBool, consistent_hash_enabled) + MEMC_SESSION_INI_ENTRY("number_of_replicas", "0", OnUpdateLongGEZero, number_of_replicas) + MEMC_SESSION_INI_ENTRY("randomize_replica_read", "0", OnUpdateLongGEZero, randomize_replica_read_enabled) + MEMC_SESSION_INI_ENTRY("remove_failed_servers", "0", OnUpdateBool, remove_failed_servers_enabled) + MEMC_SESSION_INI_ENTRY("server_failure_limit", "0", OnUpdateLongGEZero, server_failure_limit) + MEMC_SESSION_INI_ENTRY("connect_timeout", "0", OnUpdateLongGEZero, connect_timeout) + MEMC_SESSION_INI_ENTRY("sasl_username", "", OnUpdateString, sasl_username) + MEMC_SESSION_INI_ENTRY("sasl_password", "", OnUpdateString, sasl_password) + MEMC_SESSION_INI_ENTRY("prefix", "memc.sess.", OnUpdateString, prefix) + MEMC_SESSION_INI_ENTRY("persistent", "0", OnUpdateBool, persistent_enabled) #endif -#endif - STD_PHP_INI_ENTRY("memcached.compression_type", "fastlz", PHP_INI_ALL, OnUpdateCompressionType, compression_type, zend_php_memcached_globals, php_memcached_globals) - STD_PHP_INI_ENTRY("memcached.compression_factor", "1.3", PHP_INI_ALL, OnUpdateReal, compression_factor, zend_php_memcached_globals, php_memcached_globals) - STD_PHP_INI_ENTRY("memcached.compression_threshold", "2000", PHP_INI_ALL, OnUpdateLong, compression_threshold, zend_php_memcached_globals, php_memcached_globals) - STD_PHP_INI_ENTRY("memcached.serializer", SERIALIZER_DEFAULT_NAME, PHP_INI_ALL, OnUpdateSerializer, serializer_name, zend_php_memcached_globals, php_memcached_globals) -#if HAVE_MEMCACHED_SASL - STD_PHP_INI_ENTRY("memcached.use_sasl", "0", PHP_INI_SYSTEM, OnUpdateBool, use_sasl, zend_php_memcached_globals, php_memcached_globals) -#endif - STD_PHP_INI_ENTRY("memcached.store_retry_count", "2", PHP_INI_ALL, OnUpdateLong, store_retry_count, zend_php_memcached_globals, php_memcached_globals) + MEMC_INI_ENTRY("compression_type", "fastlz", OnUpdateCompressionType, compression_type) + MEMC_INI_ENTRY("compression_factor", "1.3", OnUpdateReal, compression_factor) + MEMC_INI_ENTRY("compression_threshold", "2000", OnUpdateLong, compression_threshold) + MEMC_INI_ENTRY("serializer", SERIALIZER_DEFAULT_NAME, OnUpdateSerializer, serializer_name) + MEMC_INI_ENTRY("use_sasl", "0", OnUpdateBool, sasl_enabled) + MEMC_INI_ENTRY("store_retry_count", "2", OnUpdateLong, store_retry_count) + PHP_INI_END() /* }}} */ +#undef MEMC_INI_ENTRY +#undef MEMC_SESSION_INI_ENTRY + /**************************************** Forward declarations ****************************************/ static int php_memc_handle_error(php_memc_t *i_obj, memcached_return status); -static char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t *flags, enum memcached_serializer serializer, enum memcached_compression_type compression_type); -static int php_memc_zval_from_payload(zval *value, const char *payload, size_t payload_len, uint32_t flags, enum memcached_serializer serializer); + static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key); static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key); static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool by_key); @@ -327,6 +375,14 @@ static memcached_return php_memc_do_stats_callback(const memcached_st *ptr, php_ static memcached_return php_memc_do_version_callback(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context); static void php_memc_destroy(struct memc_obj *m_obj, zend_bool persistent); + +static + zend_bool s_memcached_result_to_zval(memcached_result_st *result, zval *return_value); + +static + zend_string *s_zval_to_payload(zval *value, uint32_t *flags, enum memcached_serializer serializer, enum memcached_compression_type compression_type); + + /**************************************** Method implementations ****************************************/ @@ -391,7 +447,7 @@ static zend_bool php_memcached_on_new_callback(zval *object, zend_fcall_info *fc efree (buf); ret = 0; } - + if (Z_TYPE(retval) != IS_UNDEF) zval_ptr_dtor(&retval); @@ -400,7 +456,7 @@ static zend_bool php_memcached_on_new_callback(zval *object, zend_fcall_info *fc return ret; } -static int le_memc, le_memc_sess; +static int le_memc; static int php_memc_list_entry(void) { @@ -443,7 +499,6 @@ static PHP_METHOD(Memcached, __construct) } i_obj->is_persistent = is_persistent; - array_init(&i_obj->last_udf_flags); if (!m_obj) { m_obj = pecalloc(1, sizeof(*m_obj), is_persistent); @@ -533,217 +588,211 @@ static PHP_METHOD(Memcached, __construct) } /* }}} */ -/* {{{ Memcached::getLastUserFlags() - Returns the user flags from last fetch operation */ -PHP_METHOD(Memcached, getLastUserFlags) +static +void s_uint64_to_zval (zval *target, uint64_t value) { - MEMC_METHOD_INIT_VARS; + if (value >= LONG_MAX) { + char *buffer; + spprintf (&buffer, 0, "%" PRIu64, value); + ZVAL_STRING (target, buffer); + efree(buffer); + } + else { + ZVAL_LONG (target, (zend_long) value); + } +} - if (zend_parse_parameters_none() == FAILURE) { +typedef struct { + + size_t num_valid_keys; + + const char **mkeys; + size_t *mkeys_len; + + zend_string **strings; + +} php_memcached_keys; + +static +void s_hash_to_keys(php_memcached_keys *keys_out, HashTable *hash_in, zend_bool preserve_order, zval *return_value) +{ + size_t idx = 0, alloc_count; + zval *zv; + + keys_out->num_valid_keys = 0; + + alloc_count = zend_hash_num_elements(hash_in); + if (!alloc_count) { return; } + keys_out->mkeys = ecalloc (alloc_count, sizeof (char *)); + keys_out->mkeys_len = ecalloc (alloc_count, sizeof (size_t)); + keys_out->strings = ecalloc (alloc_count, sizeof (zend_string *)); - MEMC_METHOD_FETCH_OBJECT; - RETVAL_ZVAL(&i_obj->last_udf_flags, 1, 0); -} -/* }}} */ + ZEND_HASH_FOREACH_VAL(hash_in, zv) { + zend_string *key = zval_get_string(zv); + if (preserve_order && return_value) { + add_assoc_null_ex(return_value, key->val, key->len); + } -/* {{{ Memcached::get(string key [, mixed callback [, double &cas_token ] ]) - Returns a value for the given key or false */ -PHP_METHOD(Memcached, get) -{ - php_memc_get_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); + if (key->len > 0 && key->len < MEMCACHED_MAX_KEY) { + keys_out->mkeys[idx] = key->val; + keys_out->mkeys_len[idx] = key->len; + + keys_out->strings[idx] = key; + idx++; + } + else { + zend_string_release (key); + } + + } ZEND_HASH_FOREACH_END(); + + if (!idx) { + efree (keys_out->mkeys); + efree (keys_out->mkeys_len); + efree (keys_out->strings); + } + keys_out->num_valid_keys = idx; } -/* }}} */ -/* {{{ Memcached::getByKey(string server_key, string key [, mixed callback [, double &cas_token ] ]) - Returns a value for key from the server identified by the server key or false */ -PHP_METHOD(Memcached, getByKey) +static +void s_clear_keys(php_memcached_keys *keys) { - php_memc_get_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); + size_t i; + for (i = 0; i < keys->num_valid_keys; i++) { + zend_string_release (keys->strings[i]); + } + efree(keys->strings); + efree(keys->mkeys); + efree(keys->mkeys_len); } -/* }}} */ -/* {{{ -- php_memc_get_impl */ -static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) +static +memcached_return s_memcached_get_multi(memcached_st *memc, HashTable *hash_keys, zend_string *server_key, zend_long get_flags, zval *return_value) { - zend_string *key; - zend_string *server_key = NULL; - const char *payload = NULL; - size_t payload_len = 0; - uint32_t flags = 0; - uint64_t cas = 0; - const char* keys[1] = { NULL }; - size_t key_lens[1] = { 0 }; - zval *cas_token = NULL; + php_memcached_keys keys = { 0 }; + zval values; + + memcached_return rc, status = MEMCACHED_SUCCESS; + + size_t num_keys; uint64_t orig_cas_flag; - zend_fcall_info fci = empty_fcall_info; - zend_fcall_info_cache fcc = empty_fcall_info_cache; memcached_result_st result; - memcached_return status = MEMCACHED_SUCCESS; - MEMC_METHOD_INIT_VARS; - if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|f!z", &server_key, &key, &fci, &fcc, &cas_token) == FAILURE) { - return; - } - } else { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|f!z", &key, &fci, &fcc, &cas_token) == FAILURE) { - return; - } - } + zend_bool extended = (get_flags & MEMC_GET_EXTENDED); + zend_bool preserve_order = (get_flags & MEMC_GET_PRESERVE_ORDER); - MEMC_METHOD_FETCH_OBJECT; - i_obj->rescode = MEMCACHED_SUCCESS; - - zend_hash_clean(Z_ARRVAL(i_obj->last_udf_flags)); + array_init(&values); + s_hash_to_keys(&keys, hash_keys, preserve_order, &values); - if (key->len == 0 || (!memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) && strchr(key->val, ' '))) { - i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; - RETURN_FROM_GET; + if (!keys.num_valid_keys) { + zval_ptr_dtor(&values); + return MEMCACHED_NO_KEY_PROVIDED; } - keys[0] = key->val; - key_lens[0] = key->len; + orig_cas_flag = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS); - orig_cas_flag = memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS); - - /* - * Enable CAS support, but only if it is currently disabled. - */ - if (cas_token && Z_ISREF_P(cas_token) && orig_cas_flag == 0) { - memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1); + if (extended && !orig_cas_flag) { + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1); } - if (by_key) { - status = memcached_mget_by_key(m_obj->memc, server_key->val, server_key->len, keys, key_lens, 1); + if (server_key) { + status = memcached_mget_by_key(memc, server_key->val, server_key->len, keys.mkeys, keys.mkeys_len, keys.num_valid_keys); } else { - status = memcached_mget(m_obj->memc, keys, key_lens, 1); - } - if (cas_token && Z_ISREF_P(cas_token) && orig_cas_flag == 0) { - memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, orig_cas_flag); + status = memcached_mget(memc, keys.mkeys, keys.mkeys_len, keys.num_valid_keys); } - if (php_memc_handle_error(i_obj, status) < 0) { - RETURN_FROM_GET; + s_clear_keys(&keys); + + if (extended && !orig_cas_flag) { + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 0); } - status = MEMCACHED_SUCCESS; - memcached_result_create(m_obj->memc, &result); + memcached_result_create(memc, &result); + while ((memcached_fetch_result(memc, &result, &rc)) != NULL) { - if (memcached_fetch_result(m_obj->memc, &result, &status) == NULL) { - /* This is for historical reasons */ - if (status == MEMCACHED_END) - status = MEMCACHED_NOTFOUND; + const char *res_key = NULL; + size_t res_key_len = 0; + zval value; - /* - * If the result wasn't found, and we have the read-through callback, invoke - * it to get the value. The CAS token will be 0, because we cannot generate it - * ourselves. - */ - if (cas_token) { - ZVAL_DEREF(cas_token); - zval_ptr_dtor(cas_token); - ZVAL_DOUBLE(cas_token, 0.0); + /* For some reason instead of success it's end */ + if (rc == MEMCACHED_END) { + rc = MEMCACHED_SUCCESS; } - if (status == MEMCACHED_NOTFOUND && fci.size != 0) { - status = php_memc_do_cache_callback(getThis(), &fci, &fcc, key, return_value); + if (rc != MEMCACHED_SUCCESS) { + status = rc; + continue; } - if (php_memc_handle_error(i_obj, status) < 0) { - memcached_result_free(&result); - RETURN_FROM_GET; - } + ZVAL_UNDEF(&value); + if (!s_memcached_result_to_zval(&result, &value)) { + if (EG(exception)) { + status = MEMC_RES_PAYLOAD_FAILURE; - /* if we have a callback, all processing is done */ - if (fci.size != 0) { - memcached_result_free(&result); - return; + memcached_result_free(&result); + memcached_quit(memc); + zval_ptr_dtor (&values); + break; + } + status = MEMCACHED_SOME_ERRORS; + continue; } - } - /* Fetch all remaining results */ - memcached_result_st dummy_result; - memcached_return dummy_status = MEMCACHED_SUCCESS; - memcached_result_create(m_obj->memc, &dummy_result); - while (memcached_fetch_result(m_obj->memc, &dummy_result, &dummy_status) != NULL) {} - memcached_result_free(&dummy_result); + res_key = memcached_result_key_value(&result); + res_key_len = memcached_result_key_length(&result); - payload = memcached_result_value(&result); - payload_len = memcached_result_length(&result); - flags = memcached_result_flags(&result); - if (cas_token) { - cas = memcached_result_cas(&result); - } + if (extended) { + uint32_t flags; + uint64_t cas; + zval cas_token, node; - if (php_memc_zval_from_payload(return_value, payload, payload_len, flags, m_obj->serializer) < 0) { - memcached_result_free(&result); - i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE; - RETURN_FROM_GET; - } + cas = memcached_result_cas(&result); + flags = memcached_result_flags(&result); - if (cas_token) { - ZVAL_DEREF(cas_token); - zval_ptr_dtor(cas_token); - ZVAL_DOUBLE(cas_token, (double)cas); - } + s_uint64_to_zval (&cas_token, cas); - /* Parse user flags */ - add_assoc_long_ex(&i_obj->last_udf_flags, key->val, key->len, MEMC_VAL_GET_USER_FLAGS(flags)); + array_init (&node); + add_assoc_zval (&node, "value", &value); + add_assoc_zval (&node, "cas", &cas_token); + add_assoc_long (&node, "flags", (zend_long) MEMC_VAL_GET_USER_FLAGS(flags)); + + add_assoc_zval_ex(&values, res_key, res_key_len, &node); + } + else { + add_assoc_zval_ex(&values, res_key, res_key_len, &value); + } + } memcached_result_free(&result); -} -/* }}} */ -/* {{{ Memcached::getMulti(array keys [, array &cas_tokens ]) - Returns values for the given keys or false */ -PHP_METHOD(Memcached, getMulti) -{ - php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); + if (Z_TYPE(values) != IS_UNDEF) { + ZVAL_ZVAL(return_value, &values, 0, 0); + } + return status; } -/* }}} */ -/* {{{ Memcached::getMultiByKey(string server_key, array keys [, array &cas_tokens ]) - Returns values for the given keys from the server identified by the server key or false */ -PHP_METHOD(Memcached, getMultiByKey) -{ - php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); -} -/* }}} */ -/* {{{ -- php_memc_getMulti_impl */ -static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) +static +void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { - zval *keys = NULL; + zend_long get_flags = 0; + zend_string *key; zend_string *server_key = NULL; - size_t num_keys = 0; - zval *entry = NULL; - const char *payload = NULL; - size_t payload_len = 0; - const char **mkeys = NULL; - size_t *mkeys_len = NULL; - const char *tmp_key = NULL; - size_t res_key_len = 0; - uint32_t flags; - uint64_t cas = 0; - zval *cas_tokens = NULL; - uint64_t orig_cas_flag = 0; - zval value; - long get_flags = 0; - int i = 0; - zend_bool preserve_order; - memcached_result_st result; memcached_return status = MEMCACHED_SUCCESS; + zend_fcall_info fci = empty_fcall_info; + zend_fcall_info_cache fcc = empty_fcall_info_cache; + HashTable keys; + zval values, tmp; MEMC_METHOD_INIT_VARS; if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa/|zl", &server_key, - &keys, &cas_tokens, &get_flags) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|f!l", &server_key, &key, &fci, &fcc, &get_flags) == FAILURE) { return; } } else { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|zl", &keys, &cas_tokens, &get_flags) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|f!l", &key, &fci, &fcc, &get_flags) == FAILURE) { return; } } @@ -751,157 +800,110 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke MEMC_METHOD_FETCH_OBJECT; i_obj->rescode = MEMCACHED_SUCCESS; - /* clean flags */ - zend_hash_clean(Z_ARRVAL(i_obj->last_udf_flags)); + zend_hash_init (&keys, 1, 0, NULL, 0); + ZVAL_STR(&tmp, key); + zend_hash_add(&keys, key, &tmp); - preserve_order = (get_flags & MEMC_GET_PRESERVE_ORDER); - num_keys = zend_hash_num_elements(Z_ARRVAL_P(keys)); - mkeys = safe_emalloc(num_keys, sizeof(*mkeys), 0); - mkeys_len = safe_emalloc(num_keys, sizeof(*mkeys_len), 0); - array_init(return_value); + ZVAL_UNDEF(&values); + status = s_memcached_get_multi(m_obj->memc, &keys, server_key, get_flags, &values); + zend_hash_destroy (&keys); - /* - * Create the array of keys for libmemcached. If none of the keys were valid - * (strings), set bad key result code and return. - */ - ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(keys), entry) { - if (Z_TYPE_P(entry) != IS_STRING) { - convert_to_string_ex(entry); - } - - if (Z_TYPE_P(entry) == IS_STRING && Z_STRLEN_P(entry) > 0) { - mkeys[i] = Z_STRVAL_P(entry); - mkeys_len[i] = Z_STRLEN_P(entry); - - if (preserve_order) { - add_assoc_null_ex(return_value, mkeys[i], mkeys_len[i]); - } - i++; - } - } ZEND_HASH_FOREACH_END(); - - if (i == 0) { - i_obj->rescode = MEMCACHED_NOTFOUND; - efree(mkeys); - efree(mkeys_len); - return; + if (EG(exception)) { + zval_ptr_dtor(&values); + RETURN_FROM_GET; } - /* - * Enable CAS support, but only if it is currently disabled. - */ - if (cas_tokens && Z_ISREF_P(cas_tokens)) { - orig_cas_flag = memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS); - if (orig_cas_flag == 0) { - memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1); + if (status == MEMCACHED_SUCCESS) { + zval *zv = zend_hash_find (Z_ARRVAL(values), key); + if (zv) { + RETVAL_ZVAL(zv, 1, 0); + zval_ptr_dtor(&values); + return; + } + else { + status = MEMCACHED_NOTFOUND; } } - if (by_key) { - status = memcached_mget_by_key(m_obj->memc, server_key->val, server_key->len, mkeys, mkeys_len, i); - } else { - status = memcached_mget(m_obj->memc, mkeys, mkeys_len, i); + if (Z_TYPE(values) != IS_UNDEF) { + zval_ptr_dtor(&values); } - /* Handle error, but ignore, there might still be some result */ - php_memc_handle_error(i_obj, status); - /* - * Restore the CAS support flag, but only if we had to turn it on. - */ - if (cas_tokens && Z_ISREF_P(cas_tokens) && orig_cas_flag == 0) { - memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, orig_cas_flag); + if (status == MEMCACHED_NOTFOUND && fci.size > 0) { + // try to invoke cache cb + status = php_memc_do_cache_callback(getThis(), &fci, &fcc, key, return_value); } - efree(mkeys); - efree(mkeys_len); - - /* - * Iterate through the result set and create the result array. The CAS tokens are - * returned as doubles, because we cannot store potential 64-bit values in longs. - */ - if (cas_tokens) { - if (Z_ISREF_P(cas_tokens)) { - /* cas_tokens was passed by reference, we'll create an array for it. */ - ZVAL_DEREF(cas_tokens); - SEPARATE_ZVAL(cas_tokens); - zval_dtor(cas_tokens); - array_init(cas_tokens); - } else { - /* Not passed by reference, we allow this (eg.: if you specify null - to not enable cas but you want to use the udf_flags parameter). - We destruct it and set it to null for the peace of mind. */ - cas_tokens = NULL; - } + if (php_memc_handle_error(i_obj, status) < 0) { + RETURN_FROM_GET; } +} - /* - * Iterate through the result set and create the result array. The flags are - * returned as longs. - */ - - memcached_result_create(m_obj->memc, &result); - while ((memcached_fetch_result(m_obj->memc, &result, &status)) != NULL) { - char res_key [MEMCACHED_MAX_KEY]; - - if (status != MEMCACHED_SUCCESS) { - status = MEMCACHED_SOME_ERRORS; - php_memc_handle_error(i_obj, status); - continue; - } - - payload = memcached_result_value(&result); - payload_len = memcached_result_length(&result); - flags = memcached_result_flags(&result); - tmp_key = memcached_result_key_value(&result); - res_key_len = memcached_result_key_length(&result); - - /* - * This may be a bug in libmemcached, the key is not null terminated - * whe using the binary protocol. - */ - memcpy (res_key, tmp_key, res_key_len >= MEMCACHED_MAX_KEY ? MEMCACHED_MAX_KEY - 1 : res_key_len); - res_key [res_key_len] = '\0'; +/* {{{ Memcached::get(string key [, mixed callback [, int get_flags = 0]) + Returns a value for the given key or false */ +PHP_METHOD(Memcached, get) +{ + php_memc_get_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); +} +/* }}} */ - if (php_memc_zval_from_payload(&value, payload, payload_len, flags, m_obj->serializer) < 0) { - zval_ptr_dtor(&value); - if (EG(exception)) { - status = MEMC_RES_PAYLOAD_FAILURE; - php_memc_handle_error(i_obj, status); - memcached_quit(m_obj->memc); +/* {{{ Memcached::getByKey(string server_key, string key [, mixed callback [, int get_flags = 0]) + Returns a value for key from the server identified by the server key or false */ +PHP_METHOD(Memcached, getByKey) +{ + php_memc_get_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); +} +/* }}} */ - break; - } - status = MEMCACHED_SOME_ERRORS; - i_obj->rescode = MEMCACHED_SOME_ERRORS; +/* {{{ -- php_memc_getMulti_impl */ +static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) +{ + zval *keys = NULL; + zend_string *server_key = NULL; + zend_bool extended_results = 0; + memcached_return rc; + zend_long flags = 0; + MEMC_METHOD_INIT_VARS; - continue; + if (by_key) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa/|l", &server_key, + &keys, &flags) == FAILURE) { + return; } - - add_assoc_zval_ex(return_value, res_key, res_key_len, &value); - if (cas_tokens) { - cas = memcached_result_cas(&result); - add_assoc_double_ex(cas_tokens, res_key, res_key_len, (double)cas); + } else { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|l", &keys, &flags) == FAILURE) { + return; } - add_assoc_long_ex(&i_obj->last_udf_flags, res_key, res_key_len, MEMC_VAL_GET_USER_FLAGS(flags)); } - memcached_result_free(&result); + MEMC_METHOD_FETCH_OBJECT; + + rc = s_memcached_get_multi(m_obj->memc, Z_ARRVAL_P(keys), server_key, flags, return_value); + php_memc_handle_error(i_obj, rc); if (EG(exception)) { - /* XXX: cas_tokens should only be set on success, currently we're destructive */ - if (cas_tokens) { - ZVAL_DEREF(cas_tokens); - SEPARATE_ZVAL(cas_tokens); - zval_dtor(cas_tokens); - ZVAL_NULL(cas_tokens); - } - zend_hash_clean(Z_ARRVAL(i_obj->last_udf_flags)); zval_dtor(return_value); RETURN_FALSE; } } /* }}} */ +/* {{{ Memcached::getMulti(array keys[, long flags = 0 ]) + Returns values for the given keys or false */ +PHP_METHOD(Memcached, getMulti) +{ + php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); +} +/* }}} */ + +/* {{{ Memcached::getMultiByKey(string server_key, array keys[, long flags = 0 ]) + Returns values for the given keys from the server identified by the server key or false */ +PHP_METHOD(Memcached, getMultiByKey) +{ + php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); +} +/* }}} */ + /* {{{ Memcached::getDelayed(array keys [, bool with_cas [, mixed callback ] ]) Sends a request for the given keys and returns immediately */ PHP_METHOD(Memcached, getDelayed) @@ -1075,9 +1077,8 @@ PHP_METHOD(Memcached, fetch) res_key_len = memcached_result_key_length(&result); cas = memcached_result_cas(&result); - if (php_memc_zval_from_payload(&value, payload, payload_len, flags, m_obj->serializer) < 0) { + if (!s_memcached_result_to_zval(&result, &value)) { memcached_result_free(&result); - zval_ptr_dtor(&value); i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE; RETURN_FALSE; } @@ -1130,9 +1131,8 @@ PHP_METHOD(Memcached, fetchAll) res_key_len = memcached_result_key_length(&result); cas = memcached_result_cas(&result); - if (php_memc_zval_from_payload(&value, payload, payload_len, flags, m_obj->serializer) < 0) { + if (!s_memcached_result_to_zval(&result, &value)) { memcached_result_free(&result); - zval_ptr_dtor(&value); zval_dtor(return_value); i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE; RETURN_FALSE; @@ -1242,11 +1242,10 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke zval *entries; zend_string *server_key = NULL; time_t expiration = 0; - zval *entry; + zval *value; zend_string *skey, *str_key = NULL; ulong num_key; - char *payload; - size_t payload_len; + zend_string *payload; uint32_t flags = 0; uint32_t retry = 0; memcached_return status; @@ -1268,7 +1267,7 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke MEMC_METHOD_FETCH_OBJECT; i_obj->rescode = MEMCACHED_SUCCESS; - ZEND_HASH_FOREACH_KEY_VAL (Z_ARRVAL_P(entries), num_key, skey, entry) { + ZEND_HASH_FOREACH_KEY_VAL (Z_ARRVAL_P(entries), num_key, skey, value) { if (skey) { str_key = skey; } else if (num_key || num_key == 0) { @@ -1291,7 +1290,7 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) m_obj->set_udf_flags)); } - payload = php_memc_zval_to_payload(entry, &payload_len, &flags, m_obj->serializer, m_obj->compression_type); + payload = s_zval_to_payload(value, &flags, m_obj->serializer, m_obj->compression_type); if (payload == NULL) { i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE; if (!skey) { @@ -1302,9 +1301,9 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke retry: if (!by_key) { - status = memcached_set(m_obj->memc, str_key->val, str_key->len, payload, payload_len, expiration, flags); + status = memcached_set(m_obj->memc, str_key->val, str_key->len, payload->val, payload->len, expiration, flags); } else { - status = memcached_set_by_key(m_obj->memc, server_key->val, server_key->len, str_key->val, str_key->len, payload, payload_len, expiration, flags); + status = memcached_set_by_key(m_obj->memc, server_key->val, server_key->len, str_key->val, str_key->len, payload->val, payload->len, expiration, flags); } if (php_memc_handle_error(i_obj, status) < 0) { @@ -1312,13 +1311,13 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke if (!skey) { zend_string_release(str_key); } - efree(payload); + zend_string_release(payload); RETURN_FALSE; } if (!skey) { zend_string_release(str_key); } - efree(payload); + zend_string_release(payload); } ZEND_HASH_FOREACH_END(); RETURN_TRUE; @@ -1395,11 +1394,10 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool zend_string *key; zend_string *server_key = NULL; zend_string *s_value; - zval s_zvalue; + zval s_zvalue; zval *value; - long expiration = 0; - char *payload = NULL; - size_t payload_len; + zend_long expiration = 0; + zend_string *payload = NULL; uint32_t flags = 0; uint32_t retry = 0; memcached_return status; @@ -1474,8 +1472,9 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool php_error_docref(NULL, E_WARNING, "using touch command with binary protocol is not recommended with libmemcached versions below 1.0.16"); } #endif - } else { - payload = php_memc_zval_to_payload(value, &payload_len, &flags, m_obj->serializer, m_obj->compression_type); + } + else { + payload = s_zval_to_payload(value, &flags, m_obj->serializer, m_obj->compression_type); if (payload == NULL) { i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE; RETURN_FALSE; @@ -1485,10 +1484,10 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool switch (op) { case MEMC_OP_SET: if (!server_key) { - status = memcached_set(m_obj->memc, key->val, key->len, payload, payload_len, expiration, flags); + status = memcached_set(m_obj->memc, key->val, key->len, payload->val, payload->len, expiration, flags); } else { status = memcached_set_by_key(m_obj->memc, server_key->val, server_key->len, key->val, - key->len, payload, payload_len, expiration, flags); + key->len, payload->val, payload->len, expiration, flags); } break; #ifdef HAVE_MEMCACHED_TOUCH @@ -1503,37 +1502,37 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool #endif case MEMC_OP_ADD: if (!server_key) { - status = memcached_add(m_obj->memc, key->val, key->len, payload, payload_len, expiration, flags); + status = memcached_add(m_obj->memc, key->val, key->len, payload->val, payload->len, expiration, flags); } else { status = memcached_add_by_key(m_obj->memc, server_key->val, server_key->len, key->val, - key->len, payload, payload_len, expiration, flags); + key->len, payload->val, payload->len, expiration, flags); } break; case MEMC_OP_REPLACE: if (!server_key) { - status = memcached_replace(m_obj->memc, key->val, key->len, payload, payload_len, expiration, flags); + status = memcached_replace(m_obj->memc, key->val, key->len, payload->val, payload->len, expiration, flags); } else { status = memcached_replace_by_key(m_obj->memc, server_key->val, server_key->len, key->val, - key->len, payload, payload_len, expiration, flags); + key->len, payload->val, payload->len, expiration, flags); } break; case MEMC_OP_APPEND: if (!server_key) { - status = memcached_append(m_obj->memc, key->val, key->len, payload, payload_len, expiration, flags); + status = memcached_append(m_obj->memc, key->val, key->len, payload->val, payload->len, expiration, flags); } else { status = memcached_append_by_key(m_obj->memc, server_key->val, server_key->len, key->val, - key->len, payload, payload_len, expiration, flags); + key->len, payload->val, payload->len, expiration, flags); } break; case MEMC_OP_PREPEND: if (!server_key) { - status = memcached_prepend(m_obj->memc, key->val, key->len, payload, payload_len, expiration, flags); + status = memcached_prepend(m_obj->memc, key->val, key->len, payload->val, payload->len, expiration, flags); } else { status = memcached_prepend_by_key(m_obj->memc, server_key->val, server_key->len, key->val, - key->len, payload, payload_len, expiration, flags); + key->len, payload->val, payload->len, expiration, flags); } break; @@ -1552,7 +1551,7 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool } if (payload) { - efree(payload); + zend_string_release(payload); } } /* }}} */ @@ -1566,8 +1565,7 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) zend_string *server_key = NULL; zval *value; time_t expiration = 0; - char *payload; - size_t payload_len; + zend_string *payload; uint32_t flags = 0; memcached_return status; MEMC_METHOD_INIT_VARS; @@ -1602,22 +1600,22 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) * php_memcached uses 16 bits internally to store type, compression and serialization info. * We use 16 upper bits to store user defined flags. */ - if (m_obj->set_udf_flags > 0) { + if (m_obj->set_udf_flags >= 0) { MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) m_obj->set_udf_flags)); } - payload = php_memc_zval_to_payload(value, &payload_len, &flags, m_obj->serializer, m_obj->compression_type); + payload = s_zval_to_payload(value, &flags, m_obj->serializer, m_obj->compression_type); if (payload == NULL) { i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE; RETURN_FALSE; } if (by_key) { - status = memcached_cas_by_key(m_obj->memc, server_key->val, server_key->len, key->val, key->len, payload, payload_len, expiration, flags, cas); + status = memcached_cas_by_key(m_obj->memc, server_key->val, server_key->len, key->val, key->len, payload->val, payload->len, expiration, flags, cas); } else { - status = memcached_cas(m_obj->memc, key->val, key->len, payload, payload_len, expiration, flags, cas); + status = memcached_cas(m_obj->memc, key->val, key->len, payload->val, payload->len, expiration, flags, cas); } - efree(payload); + zend_string_release(payload); if (php_memc_handle_error(i_obj, status) < 0) { RETURN_FALSE; } @@ -2710,7 +2708,7 @@ static PHP_METHOD(Memcached, setSaslAuthData) return; } - if (!MEMC_G(use_sasl)) { + if (!MEMC_G(sasl_enabled)) { php_error_docref(NULL, E_WARNING, "SASL support (memcached.use_sasl) isn't enabled in php.ini"); RETURN_FALSE; } @@ -2839,8 +2837,6 @@ static void php_memc_free_storage(zend_object *obj) if (i_obj->obj && !i_obj->is_persistent) { php_memc_destroy(i_obj->obj, 0); } - - zval_ptr_dtor(&i_obj->last_udf_flags); zend_object_std_dtor(&i_obj->zo); i_obj->obj = NULL; } @@ -2893,15 +2889,6 @@ ZEND_RSRC_DTOR_FUNC(php_memc_dtor) } } -ZEND_RSRC_DTOR_FUNC(php_memc_sess_dtor) -{ - if (res->ptr) { - memcached_sess *memc_sess = (memcached_sess *)res->ptr; - memcached_free(memc_sess->memc_sess); - pefree(res->ptr, 1); - res->ptr = NULL; - } -} /* }}} */ /* {{{ internal API functions */ @@ -3037,61 +3024,74 @@ static int php_memc_handle_error(php_memc_t *i_obj, memcached_return status) } static -char *s_compress_value (enum memcached_compression_type compression_type, const char *payload, size_t *payload_len, uint32_t *flags) +zend_bool s_compress_value (enum memcached_compression_type compression_type, zend_string **payload_in, uint32_t *flags) { /* status */ zend_bool compress_status = 0; + zend_string *payload = *payload_in; /* Additional 5% for the data */ - size_t buffer_size = (size_t) (((double) *payload_len * 1.05) + 1.0); - char *buffer = emalloc(sizeof(uint32_t) + buffer_size); + size_t buffer_size = (size_t) (((double) payload->len * 1.05) + 1.0); + char *buffer = emalloc(buffer_size); /* Store compressed size here */ size_t compressed_size = 0; - uint32_t plen = *payload_len; - - /* Copy the uin32_t at the beginning */ - memcpy(buffer, &plen, sizeof(uint32_t)); - buffer += sizeof(uint32_t); + uint32_t original_size = payload->len; switch (compression_type) { case COMPRESSION_TYPE_FASTLZ: - compress_status = ((compressed_size = fastlz_compress(payload, *payload_len, buffer)) > 0); - MEMC_VAL_SET_FLAG(*flags, MEMC_VAL_COMPRESSION_FASTLZ); + { + compressed_size = fastlz_compress(payload->val, payload->len, buffer); + + if (compressed_size > 0) { + compress_status = 1; + MEMC_VAL_SET_FLAG(*flags, MEMC_VAL_COMPRESSION_FASTLZ); + } + } break; case COMPRESSION_TYPE_ZLIB: - /* ZLIB returns the compressed size in this buffer */ + { compressed_size = buffer_size; + int status = compress((Bytef *) buffer, &compressed_size, (Bytef *) payload->val, payload->len); - compress_status = (compress((Bytef *)buffer, &compressed_size, (Bytef *)payload, *payload_len) == Z_OK); - MEMC_VAL_SET_FLAG(*flags, MEMC_VAL_COMPRESSION_ZLIB); + if (status == Z_OK) { + compress_status = 1; + MEMC_VAL_SET_FLAG(*flags, MEMC_VAL_COMPRESSION_ZLIB); + } + } break; default: compress_status = 0; break; } - buffer -= sizeof(uint32_t); - *payload_len = compressed_size + sizeof(uint32_t); if (!compress_status) { php_error_docref(NULL, E_WARNING, "could not compress value"); MEMC_VAL_DEL_FLAG(*flags, MEMC_VAL_COMPRESSED); - efree (buffer); - *payload_len = 0; - return NULL; + return 0; } - else if (*payload_len > (compressed_size * MEMC_G(compression_factor))) { + /* This means the value was too small to be compressed, still a success */ + if (compressed_size > (payload->len * MEMC_G(compression_factor))) { + efree(buffer); MEMC_VAL_DEL_FLAG(*flags, MEMC_VAL_COMPRESSED); - efree (buffer); - *payload_len = 0; - return NULL; + return 1; } - return buffer; + + payload = zend_string_realloc(payload, compressed_size + sizeof(uint32_t), 0); + + /* Copy the uin32_t at the beginning */ + memcpy(payload->val, &original_size, sizeof(uint32_t)); + memcpy(payload->val + sizeof (uint32_t), buffer, compressed_size); + efree(buffer); + + zend_string_forget_hash_val(payload); + *payload_in = payload; + return 1; } static @@ -3166,149 +3166,142 @@ zend_bool s_serialize_value (enum memcached_serializer serializer, zval *value, } static -char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t *flags, enum memcached_serializer serializer, enum memcached_compression_type compression_type) +zend_string *s_zval_to_payload(zval *value, uint32_t *flags, enum memcached_serializer serializer, enum memcached_compression_type compression_type) { - const char *pl; - size_t pl_len = 0; - - char *payload = NULL; - smart_str buf = {0}; - char tmp[40] = {0}; + zend_string *payload; switch (Z_TYPE_P(value)) { case IS_STRING: - pl = Z_STRVAL_P(value); - pl_len = Z_STRLEN_P(value); + payload = zval_get_string(value); MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_STRING); + MEMC_VAL_HAS_FLAG(*flags, MEMC_VAL_COMPRESSED); break; case IS_LONG: - pl_len = sprintf(tmp, "%ld", Z_LVAL_P(value)); - pl = tmp; + { + smart_str buffer = {0}; + smart_str_append_long (&buffer, Z_LVAL_P(value)); + smart_str_0(&buffer); + payload = buffer.s; + MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_LONG); + } break; case IS_DOUBLE: - php_memcached_g_fmt(tmp, Z_DVAL_P(value)); - pl = tmp; - pl_len = strlen(tmp); + { + char buffer[40]; + php_memcached_g_fmt(buffer, Z_DVAL_P(value)); + payload = zend_string_init (buffer, strlen (buffer), 0); MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_DOUBLE); + } break; case IS_TRUE: - pl_len = 1; - tmp[0] = '1'; - tmp[1] = '\0'; - pl = tmp; + payload = zend_string_init ("1", 1, 0); MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_BOOL); break; case IS_FALSE: - pl_len = 0; - tmp[0] = '\0'; - pl = tmp; + payload = zend_string_alloc (0, 0); MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_BOOL); break; default: - if (!s_serialize_value (serializer, value, &buf, flags)) { - smart_str_free(&buf); + { + smart_str buffer = {0}; + + if (!s_serialize_value (serializer, value, &buffer, flags)) { + smart_str_free(&buffer); return NULL; } - pl = buf.s->val; - pl_len = buf.s->len; + payload = buffer.s; + MEMC_VAL_HAS_FLAG(*flags, MEMC_VAL_COMPRESSED); + } break; } + zend_string_forget_hash_val(payload); /* turn off compression for values below the threshold */ - if (MEMC_VAL_HAS_FLAG(*flags, MEMC_VAL_COMPRESSED) && pl_len < MEMC_G(compression_threshold)) { + if (payload->len == 0 || payload->len < MEMC_G(compression_threshold)) { MEMC_VAL_DEL_FLAG(*flags, MEMC_VAL_COMPRESSED); } /* If we have compression flag, compress the value */ if (MEMC_VAL_HAS_FLAG(*flags, MEMC_VAL_COMPRESSED)) { /* status */ - *payload_len = pl_len; - payload = s_compress_value (compression_type, pl, payload_len, flags); - } - - /* If compression failed or value is below threshold we just use plain value */ - if (!payload || !MEMC_VAL_HAS_FLAG(*flags, MEMC_VAL_COMPRESSED)) { - *payload_len = (uint32_t) pl_len; - payload = estrndup(pl, pl_len); + if (!s_compress_value (compression_type, &payload, flags)) { + zend_string_release(payload); + return NULL; + } } - if (buf.s) { - smart_str_free(&buf); - } return payload; } static -char *s_decompress_value (const char *payload, size_t *payload_len, uint32_t flags) +zend_string *s_decompress_value (const char *payload, size_t payload_len, uint32_t flags) { - char *buffer = NULL; - uint32_t len; + zend_string *buffer; + + uint32_t stored_length; unsigned long length; zend_bool decompress_status = 0; + zend_bool is_fastlz = 0, is_zlib = 0; - /* Stored with newer memcached extension? */ - if (MEMC_VAL_HAS_FLAG(flags, MEMC_VAL_COMPRESSION_FASTLZ) || MEMC_VAL_HAS_FLAG(flags, MEMC_VAL_COMPRESSION_ZLIB)) { - /* This is copied from Ilia's patch */ - memcpy(&len, payload, sizeof(uint32_t)); - buffer = emalloc(len + 1); - *payload_len -= sizeof(uint32_t); - payload += sizeof(uint32_t); - length = len; - - if (MEMC_VAL_HAS_FLAG(flags, MEMC_VAL_COMPRESSION_FASTLZ)) { - decompress_status = ((length = fastlz_decompress(payload, *payload_len, buffer, len)) > 0); - } else if (MEMC_VAL_HAS_FLAG(flags, MEMC_VAL_COMPRESSION_ZLIB)) { - decompress_status = (uncompress((Bytef *)buffer, &length, (Bytef *)payload, *payload_len) == Z_OK); - } + if (payload_len < sizeof (uint32_t)) { + return NULL; } - /* Fall back to 'old style decompression' */ - if (!decompress_status) { - unsigned int factor = 1, maxfactor = 16; - int status; - - do { - length = (unsigned long)*payload_len * (1 << factor++); - buffer = erealloc(buffer, length + 1); - memset(buffer, 0, length + 1); - status = uncompress((Bytef *)buffer, (uLongf *)&length, (const Bytef *)payload, *payload_len); - } while ((status==Z_BUF_ERROR) && (factor < maxfactor)); - - if (status == Z_OK) { - decompress_status = 1; - } + is_fastlz = MEMC_VAL_HAS_FLAG(flags, MEMC_VAL_COMPRESSION_FASTLZ); + is_zlib = MEMC_VAL_HAS_FLAG(flags, MEMC_VAL_COMPRESSION_ZLIB); + + if (!is_fastlz && !is_zlib) { + php_error_docref(NULL, E_WARNING, "could not decompress value: unrecognised encryption type"); + return NULL; + } + + memcpy(&stored_length, payload, sizeof (uint32_t)); + + payload += sizeof (uint32_t); + payload_len -= sizeof (uint32_t); + + buffer = zend_string_alloc (stored_length, 0); + + if (is_fastlz) { + decompress_status = ((length = fastlz_decompress(payload, payload_len, &buffer->val, buffer->len)) > 0); + } + else if (is_zlib) { + decompress_status = (uncompress((Bytef *) buffer->val, &buffer->len, (Bytef *)payload, payload_len) == Z_OK); } if (!decompress_status) { php_error_docref(NULL, E_WARNING, "could not decompress value"); - efree(buffer); + zend_string_release (buffer); return NULL; } - buffer [length] = '\0'; - *payload_len = length; + + zend_string_forget_hash_val(buffer); return buffer; } static -zend_bool s_unserialize_value (enum memcached_serializer serializer, int val_type, zval *value, const char *payload, size_t payload_len) +zend_bool s_unserialize_value (int val_type, zend_string *payload, zval *return_value) { switch (val_type) { case MEMC_VAL_IS_SERIALIZED: { - const char *payload_tmp = payload; php_unserialize_data_t var_hash; + const unsigned char *p, *max; + + p = (const unsigned char *) payload->val; + max = p + payload->len; PHP_VAR_UNSERIALIZE_INIT(var_hash); - if (!php_var_unserialize(value, (const unsigned char **)&payload_tmp, (const unsigned char *)payload_tmp + payload_len, &var_hash)) { - zval_ptr_dtor(value); - ZVAL_FALSE(value); + if (!php_var_unserialize(return_value, &p, max, &var_hash)) { + zval_ptr_dtor(return_value); + ZVAL_FALSE(return_value); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); php_error_docref(NULL, E_WARNING, "could not unserialize value"); return 0; @@ -3319,13 +3312,13 @@ zend_bool s_unserialize_value (enum memcached_serializer serializer, int val_typ case MEMC_VAL_IS_IGBINARY: #ifdef HAVE_MEMCACHED_IGBINARY - if (igbinary_unserialize((uint8_t *)payload, payload_len, &value)) { - ZVAL_FALSE(value); + if (igbinary_unserialize((uint8_t *) payload->val, payload->len, &value)) { + ZVAL_FALSE(return_value); php_error_docref(NULL, E_WARNING, "could not unserialize value with igbinary"); return 0; } #else - ZVAL_FALSE(value); + ZVAL_FALSE(return_value); php_error_docref(NULL, E_WARNING, "could not unserialize value, no igbinary support"); return 0; #endif @@ -3333,9 +3326,9 @@ zend_bool s_unserialize_value (enum memcached_serializer serializer, int val_typ case MEMC_VAL_IS_JSON: #ifdef HAVE_JSON_API - php_json_decode(value, (char*) payload, payload_len, (serializer == SERIALIZER_JSON_ARRAY), PHP_JSON_PARSER_DEFAULT_DEPTH); + php_json_decode(return_value, payload->val, payload->len, (serializer == SERIALIZER_JSON_ARRAY), PHP_JSON_PARSER_DEFAULT_DEPTH); #else - ZVAL_FALSE(value); + ZVAL_FALSE(return_value); php_error_docref(NULL, E_WARNING, "could not unserialize value, no json support"); return 0; #endif @@ -3343,9 +3336,9 @@ zend_bool s_unserialize_value (enum memcached_serializer serializer, int val_typ case MEMC_VAL_IS_MSGPACK: #ifdef HAVE_MEMCACHED_MSGPACK - php_msgpack_unserialize(value, payload, payload_len); + php_msgpack_unserialize(return_value, payload->val, payload->len); #else - ZVAL_FALSE(value); + ZVAL_FALSE(return_value); php_error_docref(NULL, E_WARNING, "could not unserialize value, no msgpack support"); return 0; #endif @@ -3354,117 +3347,85 @@ zend_bool s_unserialize_value (enum memcached_serializer serializer, int val_typ return 1; } -/* The caller MUST free the payload */ -static int php_memc_zval_from_payload(zval *value, const char *payload_in, size_t payload_len, uint32_t flags, enum memcached_serializer serializer) +static +zend_bool s_memcached_result_to_zval(memcached_result_st *result, zval *return_value) { - /* - A NULL payload is completely valid if length is 0, it is simply empty. - */ - int retval = 0; - zend_bool payload_emalloc = 0; - char *pl = NULL; - - if (payload_in == NULL && payload_len > 0) { - ZVAL_FALSE(value); - php_error_docref(NULL, E_WARNING, - "Could not handle non-existing value of length %zu", payload_len); - return -1; - } else if (payload_in == NULL) { - if (MEMC_VAL_GET_TYPE(flags) == MEMC_VAL_IS_BOOL) { - ZVAL_FALSE(value); - } else { - ZVAL_EMPTY_STRING(value); - } + zend_string *data; + const char *payload; + size_t payload_len; + uint32_t flags; + zend_bool retval = 1; + + payload = memcached_result_value(result); + payload_len = memcached_result_length(result); + flags = memcached_result_flags(result); + + if (!payload && payload_len > 0) { + php_error_docref(NULL, E_WARNING, "Could not handle non-existing value of length %zu", payload_len); return 0; } if (MEMC_VAL_HAS_FLAG(flags, MEMC_VAL_COMPRESSED)) { - char *datas = s_decompress_value (payload_in, &payload_len, flags); - if (!datas) { - ZVAL_FALSE(value); - return -1; + data = s_decompress_value (payload, payload_len, flags); + if (!data) { + return 0; } - pl = datas; - payload_emalloc = 1; } else { - pl = (char *) payload_in; + data = zend_string_init(payload, payload_len, 0); } switch (MEMC_VAL_GET_TYPE(flags)) { + case MEMC_VAL_IS_STRING: - ZVAL_STRINGL(value, pl, payload_len); + ZVAL_STR_COPY(return_value, data); break; case MEMC_VAL_IS_LONG: - { - long lval; - char conv_buf [128]; - - if (payload_len >= 128) { - php_error_docref(NULL, E_WARNING, "could not read long value, too big"); - retval = -1; - } - else { - memcpy (conv_buf, pl, payload_len); - conv_buf [payload_len] = '\0'; - - lval = strtol(conv_buf, NULL, 10); - ZVAL_LONG(value, lval); - } - } + ZVAL_LONG(return_value, strtol(data->val, NULL, 10)); break; case MEMC_VAL_IS_DOUBLE: { - char conv_buf [128]; - - if (payload_len >= 128) { - php_error_docref(NULL, E_WARNING, "could not read double value, too big"); - retval = -1; + if (payload_len == 8 && memcmp(data->val, "Infinity", 8) == 0) { + ZVAL_DOUBLE(return_value, php_get_inf()); + } + else if (payload_len == 9 && memcmp(data->val, "-Infinity", 9) == 0) { + ZVAL_DOUBLE(return_value, -php_get_inf()); + } + else if (payload_len == 3 && memcmp(data->val, "NaN", 3) == 0) { + ZVAL_DOUBLE(return_value, php_get_nan()); } else { - memcpy (conv_buf, pl, payload_len); - conv_buf [payload_len] = '\0'; - - if (payload_len == 8 && memcmp(conv_buf, "Infinity", 8) == 0) { - ZVAL_DOUBLE(value, php_get_inf()); - } else if (payload_len == 9 && memcmp(conv_buf, "-Infinity", 9) == 0) { - ZVAL_DOUBLE(value, -php_get_inf()); - } else if (payload_len == 3 && memcmp(conv_buf, "NaN", 3) == 0) { - ZVAL_DOUBLE(value, php_get_nan()); - } else { - ZVAL_DOUBLE(value, zend_strtod(conv_buf, NULL)); - } + ZVAL_DOUBLE(return_value, zend_strtod(data->val, NULL)); } } break; case MEMC_VAL_IS_BOOL: - ZVAL_BOOL(value, payload_len > 0 && pl[0] == '1'); + ZVAL_BOOL(return_value, payload_len > 0 && data->val[0] == '1'); break; case MEMC_VAL_IS_SERIALIZED: case MEMC_VAL_IS_IGBINARY: case MEMC_VAL_IS_JSON: case MEMC_VAL_IS_MSGPACK: - if (!s_unserialize_value (serializer, MEMC_VAL_GET_TYPE(flags), value, pl, payload_len)) { - retval = -1; - } + retval = s_unserialize_value (MEMC_VAL_GET_TYPE(flags), data, return_value); break; default: - ZVAL_FALSE(value); php_error_docref(NULL, E_WARNING, "unknown payload type"); - retval = -1; + retval = 0; break; } + zend_string_release(data); - if (payload_emalloc) { - efree(pl); + if (!retval) { + zval_ptr_dtor(return_value); } return retval; } + PHP_MEMCACHED_API zend_class_entry *php_memc_get_ce(void) { @@ -3508,8 +3469,7 @@ zend_class_entry *php_memc_get_exception_base(int root) static memcached_return php_memc_do_cache_callback(zval *zmemc_obj, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string *key, zval *value) { - char *payload = NULL; - size_t payload_len = 0; + zend_string *payload = NULL; zval params[4]; zval retval; zval z_key; @@ -3550,16 +3510,19 @@ static memcached_return php_memc_do_cache_callback(zval *zmemc_obj, zend_fcall_i time_t expir; expir = zval_get_long(expiration); + payload = s_zval_to_payload(value, &flags, m_obj->serializer, m_obj->compression_type); - payload = php_memc_zval_to_payload(value, &payload_len, &flags, m_obj->serializer, m_obj->compression_type); if (payload == NULL) { status = (memcached_return)MEMC_RES_PAYLOAD_FAILURE; } else { - rc = memcached_set(m_obj->memc, key->val, key->len, payload, payload_len, expir, flags); + if (m_obj->set_udf_flags >= 0) { + MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) m_obj->set_udf_flags)); + } + rc = memcached_set(m_obj->memc, key->val, key->len, payload->val, payload->len, expir, flags); if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED) { status = rc; } - efree(payload); + zend_string_release(payload); } } else { status = MEMCACHED_NOTFOUND; @@ -3616,8 +3579,7 @@ static int php_memc_do_result_callback(zval *zmemc_obj, zend_fcall_info *fci, i_obj = Z_MEMC_OBJ_P(zmemc_obj); - if (php_memc_zval_from_payload(&value, payload, payload_len, flags, i_obj->obj->serializer) < 0) { - zval_ptr_dtor(&value); + if (!s_memcached_result_to_zval(result, &value)) { i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE; return -1; } @@ -3734,27 +3696,23 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_get, 0, 0, 1) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, cache_cb) - ZEND_ARG_INFO(2, cas_token) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_getByKey, 0, 0, 2) ZEND_ARG_INFO(0, server_key) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, cache_cb) - ZEND_ARG_INFO(2, cas_token) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_getMulti, 0, 0, 1) ZEND_ARG_ARRAY_INFO(0, keys, 0) - ZEND_ARG_INFO(2, cas_tokens) - ZEND_ARG_INFO(0, flags) + ZEND_ARG_INFO(0, get_flags) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_getMultiByKey, 0, 0, 2) ZEND_ARG_INFO(0, server_key) ZEND_ARG_ARRAY_INFO(0, keys, 0) - ZEND_ARG_INFO(2, cas_tokens) - ZEND_ARG_INFO(0, flags) + ZEND_ARG_INFO(0, get_flags) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_getDelayed, 0, 0, 1) @@ -3811,9 +3769,6 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_setMultiByKey, 0, 0, 2) ZEND_ARG_INFO(0, expiration) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO_EX(arginfo_getLastUserFlags, 0, 0, 0) -ZEND_END_ARG_INFO() - ZEND_BEGIN_ARG_INFO_EX(arginfo_add, 0, 0, 2) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, value) @@ -4041,8 +3996,6 @@ static zend_function_entry memcached_class_methods[] = { MEMC_ME(setMulti, arginfo_setMulti) MEMC_ME(setMultiByKey, arginfo_setMultiByKey) - MEMC_ME(getLastUserFlags, arginfo_getLastUserFlags) - MEMC_ME(cas, arginfo_cas) MEMC_ME(casByKey, arginfo_casByKey) MEMC_ME(add, arginfo_add) @@ -4136,35 +4089,36 @@ static PHP_GINIT_FUNCTION(php_memcached) { #ifdef HAVE_MEMCACHED_SESSION - php_memcached_globals->sess_locking_enabled = 1; - php_memcached_globals->sess_binary_enabled = 1; - php_memcached_globals->sess_consistent_hash_enabled = 0; - php_memcached_globals->sess_number_of_replicas = 0; - php_memcached_globals->sess_remove_failed_enabled = 0; - php_memcached_globals->sess_prefix = NULL; - php_memcached_globals->sess_lock_wait = 0; - php_memcached_globals->sess_lock_max_wait = 0; - php_memcached_globals->sess_lock_expire = 0; - php_memcached_globals->sess_locked = 0; - php_memcached_globals->sess_lock_key = NULL; - php_memcached_globals->sess_lock_key_len = 0; - php_memcached_globals->sess_randomize_replica_read = 0; - php_memcached_globals->sess_connect_timeout = 1000; -#if HAVE_MEMCACHED_SASL - php_memcached_globals->sess_sasl_username = NULL; - php_memcached_globals->sess_sasl_password = NULL; - php_memcached_globals->sess_sasl_data = 0; -#endif + + php_memcached_globals->session_ini.lock_enabled = 0; + php_memcached_globals->session_ini.lock_wait_max = 2000; + php_memcached_globals->session_ini.lock_wait_min = 1000; + php_memcached_globals->session_ini.lock_retries = 5; + php_memcached_globals->session_ini.lock_expiration = 30; + php_memcached_globals->session_ini.compression_enabled = 1; + php_memcached_globals->session_ini.binary_protocol_enabled = 1; + php_memcached_globals->session_ini.consistent_hash_enabled = 1; + php_memcached_globals->session_ini.number_of_replicas = 0; + php_memcached_globals->session_ini.server_failure_limit = 1; + php_memcached_globals->session_ini.randomize_replica_read_enabled = 1; + php_memcached_globals->session_ini.remove_failed_servers_enabled = 1; + php_memcached_globals->session_ini.connect_timeout = 1000; + php_memcached_globals->session_ini.prefix = NULL; + php_memcached_globals->session_ini.persistent_enabled = 0; + php_memcached_globals->session_ini.sasl_username = NULL; + php_memcached_globals->session_ini.sasl_password = NULL; + #endif - php_memcached_globals->serializer_name = NULL; - php_memcached_globals->serializer = SERIALIZER_DEFAULT; - php_memcached_globals->compression_type = NULL; - php_memcached_globals->compression_type_real = COMPRESSION_TYPE_FASTLZ; - php_memcached_globals->compression_factor = 1.30; + php_memcached_globals->memc_ini.serializer_name = NULL; + php_memcached_globals->memc_ini.serializer = SERIALIZER_DEFAULT; + php_memcached_globals->memc_ini.compression_type = NULL; + php_memcached_globals->memc_ini.compression_threshold = 2000; + php_memcached_globals->memc_ini.compression_type_real = COMPRESSION_TYPE_FASTLZ; + php_memcached_globals->memc_ini.compression_factor = 1.30; + php_memcached_globals->memc_ini.store_retry_count = 2; #if HAVE_MEMCACHED_SASL - php_memcached_globals->use_sasl = 0; + php_memcached_globals->memc_ini.sasl_enabled = 0; #endif - php_memcached_globals->store_retry_count = 2; } zend_module_entry memcached_module_entry = { @@ -4374,6 +4328,7 @@ static void php_memc_register_constants(INIT_FUNC_ARGS) * Flags. */ REGISTER_MEMC_CLASS_CONST_LONG(GET_PRESERVE_ORDER, MEMC_GET_PRESERVE_ORDER); + REGISTER_MEMC_CLASS_CONST_LONG(GET_EXTENDED, MEMC_GET_EXTENDED); #ifdef HAVE_MEMCACHED_PROTOCOL /* @@ -4422,11 +4377,6 @@ static void php_memc_register_constants(INIT_FUNC_ARGS) } /* }}} */ -int php_memc_sess_list_entry(void) -{ - return le_memc_sess; -} - /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(memcached) { @@ -4438,7 +4388,6 @@ PHP_MINIT_FUNCTION(memcached) memcached_object_handlers.free_obj = php_memc_free_storage; le_memc = zend_register_list_destructors_ex(NULL, php_memc_dtor, "Memcached persistent connection", module_number); - le_memc_sess = zend_register_list_destructors_ex(NULL, php_memc_sess_dtor, "Memcached Sessions persistent connection", module_number); INIT_CLASS_ENTRY(ce, "Memcached", memcached_class_methods); memcached_ce = zend_register_internal_class(&ce); @@ -4462,12 +4411,12 @@ PHP_MINIT_FUNCTION(memcached) php_memc_register_constants(INIT_FUNC_ARGS_PASSTHRU); #ifdef HAVE_MEMCACHED_SESSION - php_session_register_module(ps_memcached_ptr); + php_memc_session_minit(module_number); #endif REGISTER_INI_ENTRIES(); #if HAVE_MEMCACHED_SASL - if (MEMC_G(use_sasl)) { + if (MEMC_G(sasl_enabled)) { if (sasl_client_init(NULL) != SASL_OK) { php_error_docref(NULL, E_ERROR, "Failed to initialize SASL library"); return FAILURE; @@ -4482,7 +4431,7 @@ PHP_MINIT_FUNCTION(memcached) PHP_MSHUTDOWN_FUNCTION(memcached) { #if HAVE_MEMCACHED_SASL - if (MEMC_G(use_sasl)) { + if (MEMC_G(sasl_enabled)) { sasl_done(); } #endif diff --git a/php_memcached_private.h b/php_memcached_private.h index ffca963d..46565e70 100644 --- a/php_memcached_private.h +++ b/php_memcached_private.h @@ -129,46 +129,60 @@ typedef struct { #endif ZEND_BEGIN_MODULE_GLOBALS(php_memcached) + #ifdef HAVE_MEMCACHED_SESSION - zend_bool sess_locking_enabled; - long sess_lock_wait; - long sess_lock_max_wait; - long sess_lock_expire; - char* sess_prefix; - zend_bool sess_locked; - char* sess_lock_key; - int sess_lock_key_len; - - int sess_number_of_replicas; - zend_bool sess_randomize_replica_read; - zend_bool sess_remove_failed_enabled; - long sess_connect_timeout; - zend_bool sess_consistent_hash_enabled; - zend_bool sess_binary_enabled; + /* Session related variables */ + struct { + zend_bool lock_enabled; + zend_long lock_wait_max; + zend_long lock_wait_min; + zend_long lock_retries; + zend_long lock_expiration; + + zend_bool compression_enabled; + zend_bool binary_protocol_enabled; + zend_bool consistent_hash_enabled; + + zend_long server_failure_limit; + zend_long number_of_replicas; + zend_bool randomize_replica_read_enabled; + zend_bool remove_failed_servers_enabled; + + zend_long connect_timeout; + + char *prefix; + zend_bool persistent_enabled; + + char *sasl_username; + char *sasl_password; + } session_ini; -#if HAVE_MEMCACHED_SASL - char *sess_sasl_username; - char *sess_sasl_password; - zend_bool sess_sasl_data; -#endif #endif - char *serializer_name; - enum memcached_serializer serializer; - char *compression_type; - int compression_type_real; - int compression_threshold; + struct { + char *serializer_name; + char *compression_type; + zend_long compression_threshold; + double compression_factor; + zend_long store_retry_count; - double compression_factor; #if HAVE_MEMCACHED_SASL - zend_bool use_sasl; + zend_bool sasl_enabled; #endif + + /* Converted values*/ + enum memcached_serializer serializer; + zend_long compression_type_real; + } memc_ini; + + + #ifdef HAVE_MEMCACHED_PROTOCOL struct { php_memc_server_cb_t callbacks [MEMC_SERVER_ON_MAX]; } server; #endif - long store_retry_count; + ZEND_END_MODULE_GLOBALS(php_memcached) PHP_RINIT_FUNCTION(memcached); @@ -177,19 +191,6 @@ PHP_MINIT_FUNCTION(memcached); PHP_MSHUTDOWN_FUNCTION(memcached); PHP_MINFO_FUNCTION(memcached); -#ifdef ZTS -#define MEMC_G(v) TSRMG(php_memcached_globals_id, zend_php_memcached_globals *, v) -#else -#define MEMC_G(v) (php_memcached_globals.v) -#endif - -typedef struct { - memcached_st *memc_sess; - zend_bool is_persistent; -} memcached_sess; - -int php_memc_sess_list_entry(void); - char *php_memc_printable_func (zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TSRMLS_DC); memcached_return php_memcached_exist (memcached_st *memc, zend_string *key); diff --git a/php_memcached_session.c b/php_memcached_session.c index 85baad03..8c6454a1 100644 --- a/php_memcached_session.c +++ b/php_memcached_session.c @@ -18,6 +18,8 @@ #include "php_memcached_private.h" #include "php_memcached_session.h" +#include "Zend/zend_smart_str_public.h" + extern ZEND_DECLARE_MODULE_GLOBALS(php_memcached) #define MEMC_SESS_DEFAULT_LOCK_WAIT 150000 @@ -27,278 +29,350 @@ ps_module ps_mod_memcached = { PS_MOD_UPDATE_TIMESTAMP(memcached) }; -static int php_memc_sess_lock(memcached_st *memc, const char *key) +typedef struct { + zend_bool is_persistent; + zend_bool has_sasl_data; + zend_bool is_locked; + zend_string *lock_key; +} php_memcached_user_data; + +#ifndef MIN +# define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +#ifndef MAX +# define MAX(a,b) (((a)>(b))?(a):(b)) +#endif + +#ifdef ZTS +#define MEMC_SESS_INI(v) TSRMG(php_memcached_globals_id, zend_php_memcached_globals *, session_ini.v) +#else +#define MEMC_SESS_INI(v) (php_memcached_globals.session_ini.v) +#endif + +#define MEMC_SESS_STR_INI(vv) ((MEMC_SESS_INI(vv) && *MEMC_SESS_INI(vv)) ? MEMC_SESS_INI(vv) : NULL) + +static + int le_memc_sess; + +static +int s_memc_sess_list_entry(void) { - char *lock_key = NULL; - int lock_key_len = 0; - unsigned long attempts; - long write_retry_attempts = 0; - long lock_maxwait = MEMC_G(sess_lock_max_wait); - long lock_wait = MEMC_G(sess_lock_wait); - long lock_expire = MEMC_G(sess_lock_expire); - time_t expiration; - memcached_return status; - /* set max timeout for session_start = max_execution_time. (c) Andrei Darashenka, Richter & Poweleit GmbH */ - if (lock_maxwait <= 0) { - lock_maxwait = zend_ini_long(ZEND_STRS("max_execution_time"), 0); - if (lock_maxwait <= 0) { - lock_maxwait = MEMC_SESS_LOCK_EXPIRATION; - } - } - if (lock_wait == 0) { - lock_wait = MEMC_SESS_DEFAULT_LOCK_WAIT; + return le_memc_sess; +} + +static +void s_destroy_mod_data(memcached_st *memc) +{ + php_memcached_user_data *user_data = memcached_get_user_data(memc); + + if (user_data->has_sasl_data) { + memcached_destroy_sasl_auth_data(memc); } - if (lock_expire <= 0) { - lock_expire = lock_maxwait; + + memcached_free(memc); + pefree(memc, user_data->is_persistent); + pefree(user_data, user_data->is_persistent); +} + +ZEND_RSRC_DTOR_FUNC(php_memc_sess_dtor) +{ + if (res->ptr) { + s_destroy_mod_data((memcached_st *) res->ptr); + res->ptr = NULL; } - expiration = lock_expire + 1; - attempts = (unsigned long)((1000000.0 / lock_wait) * lock_maxwait); +} - /* Set the number of write retry attempts to the number of replicas times the number of attempts to remove a server */ - if (MEMC_G(sess_remove_failed_enabled)) { - write_retry_attempts = MEMC_G(sess_number_of_replicas) * ( memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT) + 1); +int php_memc_session_minit(int module_number) +{ + le_memc_sess = + zend_register_list_destructors_ex(NULL, php_memc_sess_dtor, "Memcached Sessions persistent connection", module_number); + + php_session_register_module(ps_memcached_ptr); + return SUCCESS; +} + +static +time_t s_lock_expiration() +{ + zend_long max_execution_time; + + if (MEMC_SESS_INI(lock_expiration) > 0) { + return time(NULL) + MEMC_SESS_INI(lock_expiration); } + else { + zend_long max_execution_time = zend_ini_long(ZEND_STRS("max_execution_time"), 0); + if (max_execution_time > 0) { + return time(NULL) + max_execution_time; + } + } + return 0; +} + +static +zend_bool s_lock_session(memcached_st *memc, zend_string *sid) +{ + char *lock_key; + size_t lock_key_len; + time_t expiration; + zend_long wait_time, retries; + php_memcached_user_data *user_data = memcached_get_user_data(memc); + + lock_key_len = spprintf(&lock_key, 0, "lock.%s", sid->val); + expiration = s_lock_expiration(); + + wait_time = MEMC_SESS_INI(lock_wait_min); + retries = MEMC_SESS_INI(lock_retries); - lock_key_len = spprintf(&lock_key, 0, "lock.%s", key); do { - status = memcached_add(memc, lock_key, lock_key_len, "1", sizeof("1")-1, expiration, 0); - if (status == MEMCACHED_SUCCESS) { - MEMC_G(sess_locked) = 1; - MEMC_G(sess_lock_key) = lock_key; - MEMC_G(sess_lock_key_len) = lock_key_len; - return 0; - } else if (status != MEMCACHED_NOTSTORED && status != MEMCACHED_DATA_EXISTS) { - if (write_retry_attempts > 0) { - write_retry_attempts--; - continue; - } - php_error_docref(NULL, E_WARNING, "Write of lock failed"); + memcached_return rc = + memcached_add(memc, lock_key, lock_key_len, "1", sizeof ("1") - 1, expiration, 0); + + switch (rc) { + + case MEMCACHED_SUCCESS: + user_data->lock_key = zend_string_init(lock_key, lock_key_len, user_data->is_persistent); + user_data->is_locked = 1; + break; + + case MEMCACHED_NOTSTORED: + case MEMCACHED_DATA_EXISTS: + usleep(wait_time * 1000); + wait_time = MIN(MEMC_SESS_INI(lock_wait_max), wait_time * 2); break; - } - if (lock_wait > 0) { - usleep(lock_wait); + default: + php_error_docref(NULL, E_WARNING, "Failed to write session lock: %s", memcached_strerror (memc, rc)); + break; } - } while(--attempts > 0); + } while (!user_data->is_locked && retries-- > 0); efree(lock_key); - return -1; + return user_data->is_locked; } -static void php_memc_sess_unlock(memcached_st *memc) +static +void s_unlock_session(memcached_st *memc) { - if (MEMC_G(sess_locked)) { - memcached_delete(memc, MEMC_G(sess_lock_key), MEMC_G(sess_lock_key_len), 0); - MEMC_G(sess_locked) = 0; - efree(MEMC_G(sess_lock_key)); - MEMC_G(sess_lock_key_len) = 0; + php_memcached_user_data *user_data = memcached_get_user_data(memc); + + if (user_data->is_locked) { + memcached_delete(memc, user_data->lock_key->val, user_data->lock_key->len, 0); + user_data->is_locked = 0; + zend_string_release (user_data->lock_key); } } -PS_OPEN_FUNC(memcached) +static +zend_bool s_configure_from_ini_values(memcached_st *memc) { - memcached_sess *memc_sess = PS_GET_MOD_DATA(); - memcached_return status; - char *p, *plist_key = NULL; - int plist_key_len = 0; - - if (!strncmp((char *)save_path, "PERSISTENT=", sizeof("PERSISTENT=") - 1)) { - zend_resource *le = NULL; - zval *le_z = NULL; - char *e; - - p = (char *)save_path + sizeof("PERSISTENT=") - 1; - if (!*p) { -error: - php_error_docref(NULL, E_WARNING, "Invalid persistent id for session storage"); - return FAILURE; - } - if ((e = strchr(p, ' '))) { - plist_key_len = spprintf(&plist_key, 0, "memcached_sessions:id=%.*s", (int)(e - p), p); - } else { - goto error; - } - plist_key_len++; - - if ((le_z = zend_hash_str_find(&EG(persistent_list), plist_key, plist_key_len)) != NULL) { - le = Z_RES_P(le_z); - if (le->type == php_memc_sess_list_entry()) { - memc_sess = (memcached_sess *) le->ptr; - PS_SET_MOD_DATA(memc_sess); - return SUCCESS; - } - } - p = e + 1; - memc_sess = pecalloc(sizeof(*memc_sess), 1, 1); - memc_sess->is_persistent = 1; - } else { - p = (char *)save_path; - memc_sess = ecalloc(sizeof(*memc_sess), 1); - memc_sess->is_persistent = 0; - } - - if (!strstr(p, "--SERVER")) { - memcached_server_st *servers = memcached_servers_parse(p); - if (servers) { - memc_sess->memc_sess = memcached_create(NULL); - if (memc_sess->memc_sess) { - if (MEMC_G(sess_consistent_hash_enabled)) { - if (memcached_behavior_set(memc_sess->memc_sess, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, (uint64_t) 1) == MEMCACHED_FAILURE) { - PS_SET_MOD_DATA(NULL); - if (plist_key) { - efree(plist_key); - } - memcached_free(memc_sess->memc_sess); - php_error_docref(NULL, E_WARNING, "failed to enable memcached consistent hashing"); - return FAILURE; - } - } + memcached_return rc; - status = memcached_server_push(memc_sess->memc_sess, servers); - memcached_server_list_free(servers); - - if (MEMC_G(sess_prefix) && MEMC_G(sess_prefix)[0] != 0 && memcached_callback_set(memc_sess->memc_sess, MEMCACHED_CALLBACK_PREFIX_KEY, MEMC_G(sess_prefix)) != MEMCACHED_SUCCESS) { - PS_SET_MOD_DATA(NULL); - if (plist_key) { - efree(plist_key); - } - memcached_free(memc_sess->memc_sess); - php_error_docref(NULL, E_WARNING, "bad memcached key prefix in memcached.sess_prefix"); - return FAILURE; - } +#define check_set_behavior(behavior, value) \ + if ((rc = memcached_behavior_set(memc, (behavior), (value))) != MEMCACHED_SUCCESS) { \ + php_error_docref(NULL, E_WARNING, "failed to initialise session memcached configuration: %s", memcached_strerror(memc, rc)); \ + return 0; \ + } - if (status == MEMCACHED_SUCCESS) { - goto success; - } - } else { - memcached_server_list_free(servers); - php_error_docref(NULL, E_WARNING, "could not allocate libmemcached structure"); - } - } else { - php_error_docref(NULL, E_WARNING, "failed to parse session.save_path"); - } - } else { - memc_sess->memc_sess = php_memc_create_str(p, strlen(p)); - if (!memc_sess->memc_sess) { -#ifdef HAVE_LIBMEMCACHED_CHECK_CONFIGURATION - char error_buffer[1024]; - if (libmemcached_check_configuration(p, strlen(p), error_buffer, sizeof(error_buffer)) != MEMCACHED_SUCCESS) { - php_error_docref(NULL, E_WARNING, "session.save_path configuration error %s", error_buffer); - } else { - php_error_docref(NULL, E_WARNING, "failed to initialize memcached session storage"); - } -#else - php_error_docref(NULL, E_WARNING, "failed to initialize memcached session storage"); -#endif + if (MEMC_SESS_INI(binary_protocol_enabled)) { + check_set_behavior(MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1); + } - } else { -success: - PS_SET_MOD_DATA(memc_sess); + if (MEMC_SESS_INI(consistent_hash_enabled)) { + check_set_behavior(MEMCACHED_BEHAVIOR_KETAMA, 1); + } - if (plist_key) { - zend_resource le; - zend_string *tmp_key; + if (MEMC_SESS_INI(server_failure_limit)) { + check_set_behavior(MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT, MEMC_SESS_INI(server_failure_limit)); + } - le.type = php_memc_sess_list_entry(); - le.ptr = memc_sess; + if (MEMC_SESS_INI(number_of_replicas)) { + check_set_behavior(MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, MEMC_SESS_INI(number_of_replicas)); + } - tmp_key = zend_string_init(plist_key, plist_key_len, 0); - if (zend_hash_update_mem(&EG(persistent_list), tmp_key, (void *)&le, sizeof(le)) == NULL) { - zend_string_release(tmp_key); - efree(plist_key); - php_error_docref(NULL, E_ERROR, "could not register persistent entry"); - } - zend_string_release(tmp_key); - efree(plist_key); - } + if (MEMC_SESS_INI(randomize_replica_read_enabled)) { + check_set_behavior(MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ, 1); + } + + if (MEMC_SESS_INI(remove_failed_servers_enabled)) { + check_set_behavior(MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS, 1); + } + + if (MEMC_SESS_INI(connect_timeout)) { + check_set_behavior(MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT, MEMC_SESS_INI(connect_timeout)); + } + + if (MEMC_SESS_STR_INI(prefix)) { + memcached_callback_set(memc, MEMCACHED_CALLBACK_NAMESPACE, MEMC_SESS_STR_INI(prefix)); + } - if (MEMC_G(sess_binary_enabled)) { - if (memcached_behavior_set(memc_sess->memc_sess, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, (uint64_t) 1) == MEMCACHED_FAILURE) { - php_error_docref(NULL, E_WARNING, "failed to set memcached session binary protocol"); - return FAILURE; - } - } #ifdef HAVE_MEMCACHED_SASL - if (MEMC_G(use_sasl)) { - /* - * Enable SASL support if username and password are set - * - */ - if (MEMC_G(sess_sasl_username) && MEMC_G(sess_sasl_password)) { - /* Force binary protocol */ - if (memcached_behavior_set(memc_sess->memc_sess, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, (uint64_t) 1) == MEMCACHED_FAILURE) { - php_error_docref(NULL, E_WARNING, "failed to set memcached session binary protocol"); - return FAILURE; - } - if (memcached_set_sasl_auth_data(memc_sess->memc_sess, MEMC_G(sess_sasl_username), MEMC_G(sess_sasl_password)) == MEMCACHED_FAILURE) { - php_error_docref(NULL, E_WARNING, "failed to set memcached session sasl credentials"); - return FAILURE; - } - MEMC_G(sess_sasl_data) = 1; - } - } + if (MEMC_SESS_STR_INI(sasl_username) && MEMC_SESS_STR_INI(sasl_password)) { + php_memcached_user_data *user_data; + check_set_behavior(MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1); + if (memcached_set_sasl_auth_data(memc, MEMC_SESS_STR_INI(sasl_username), MEMC_SESS_STR_INI(sasl_password)) == MEMCACHED_FAILURE) { + php_error_docref(NULL, E_WARNING, "failed to set memcached session sasl credentials"); + return 0; + } + user_data = memcached_get_user_data(memc); + user_data->has_sasl_data = 1; + } #endif - if (MEMC_G(sess_number_of_replicas) > 0) { - if (memcached_behavior_set(memc_sess->memc_sess, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, (uint64_t) MEMC_G(sess_number_of_replicas)) == MEMCACHED_FAILURE) { - php_error_docref(NULL, E_WARNING, "failed to set memcached session number of replicas"); - return FAILURE; - } - if (memcached_behavior_set(memc_sess->memc_sess, MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ, (uint64_t) MEMC_G(sess_randomize_replica_read)) == MEMCACHED_FAILURE) { - php_error_docref(NULL, E_WARNING, "failed to set memcached session randomize replica read"); - } - } - if (memcached_behavior_set(memc_sess->memc_sess, MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT, (uint64_t) MEMC_G(sess_connect_timeout)) == MEMCACHED_FAILURE) { - php_error_docref(NULL, E_WARNING, "failed to set memcached connection timeout"); - return FAILURE; - } -#ifdef HAVE_MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS - /* Allow libmemcached remove failed servers */ - if (MEMC_G(sess_remove_failed_enabled)) { - if (memcached_behavior_set(memc_sess->memc_sess, MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS, (uint64_t) 1) == MEMCACHED_FAILURE) { - php_error_docref(NULL, E_WARNING, "failed to set: remove failed servers"); - return FAILURE; +#undef safe_set_behavior + + return 1; +} + +static +void *s_pemalloc_fn(const memcached_st *memc, size_t size, void *context) +{ + zend_bool *is_persistent = memcached_get_user_data(memc); + + return + pemalloc(size, *is_persistent); +} + +static +void s_pefree_fn(const memcached_st *memc, void *mem, void *context) +{ + zend_bool *is_persistent = memcached_get_user_data(memc); + + return + pefree(mem, *is_persistent); +} + +static +void *s_perealloc_fn(const memcached_st *memc, void *mem, const size_t size, void *context) +{ + zend_bool *is_persistent = memcached_get_user_data(memc); + + return + perealloc(mem, size, *is_persistent); +} + +static +void *s_pecalloc_fn(const memcached_st *memc, size_t nelem, const size_t elsize, void *context) +{ + zend_bool *is_persistent = memcached_get_user_data(memc); + + return + pecalloc(nelem, elsize, *is_persistent); +} + + +static +memcached_st *s_init_mod_data (const memcached_server_list_st servers, zend_bool is_persistent) +{ + void *buffer; + php_memcached_user_data *user_data; + memcached_st *memc; + + buffer = pecalloc(1, sizeof(memcached_st), is_persistent); + memc = memcached_create (buffer); + + if (!memc) { + php_error_docref(NULL, E_ERROR, "failed to allocate memcached structure"); + /* not reached */ + } + + memcached_set_memory_allocators(memc, s_pemalloc_fn, s_pefree_fn, s_perealloc_fn, s_pecalloc_fn, NULL); + + user_data = pecalloc(1, sizeof(php_memcached_user_data), is_persistent); + user_data->is_persistent = is_persistent; + user_data->has_sasl_data = 0; + user_data->lock_key = NULL; + user_data->is_locked = 0; + + memcached_set_user_data(memc, user_data); + memcached_server_push (memc, servers); + return memc; +} + +PS_OPEN_FUNC(memcached) +{ + memcached_st *memc = NULL; + char *plist_key = NULL; + size_t plist_key_len = 0; + memcached_server_list_st servers; + + // First parse servers + servers = memcached_servers_parse(save_path); + + if (!servers) { + php_error_docref(NULL, E_WARNING, "failed to parse session.save_path"); + PS_SET_MOD_DATA(NULL); + return FAILURE; + } + + if (MEMC_SESS_INI(persistent_enabled)) { + zend_resource *le_p; + + plist_key_len = spprintf(&plist_key, 0, "memc-session:%s", save_path); + + if ((le_p = zend_hash_str_find_ptr(&EG(persistent_list), plist_key, plist_key_len)) != NULL) { + if (le_p->type == s_memc_sess_list_entry()) { + memc = (memcached_st *) le_p->ptr; + + if (!s_configure_from_ini_values(memc)) { + // Remove existing plist entry + zend_hash_str_del(&EG(persistent_list), plist_key, plist_key_len); + memc = NULL; + } + else { + efree(plist_key); + PS_SET_MOD_DATA(memc); + return SUCCESS; } } -#endif - return SUCCESS; } } + memc = s_init_mod_data(servers, MEMC_SESS_INI(persistent_enabled)); + memcached_server_list_free(servers); + if (plist_key) { + zend_resource le; + + le.type = s_memc_sess_list_entry(); + le.ptr = memc; + + GC_REFCOUNT(&le) = 1; + + /* plist_key is not a persistent allocated key, thus we use str_update here */ + if (zend_hash_str_update_mem(&EG(persistent_list), plist_key, plist_key_len, &le, sizeof(le)) == NULL) { + php_error_docref(NULL, E_ERROR, "Could not register persistent entry for the memcached session"); + /* not reached */ + } efree(plist_key); } - PS_SET_MOD_DATA(NULL); - return FAILURE; + PS_SET_MOD_DATA(memc); + return SUCCESS; } PS_CLOSE_FUNC(memcached) { - memcached_sess *memc_sess = PS_GET_MOD_DATA(); + memcached_st *memc = PS_GET_MOD_DATA(); + php_memcached_user_data *user_data; - if (!memc_sess) { + if (!memc) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session is not allocated, check session.save_path value"); return FAILURE; } - if (MEMC_G(sess_locking_enabled)) { - php_memc_sess_unlock(memc_sess->memc_sess); + user_data = memcached_get_user_data(memc); + + if (user_data->is_locked) { + s_unlock_session(memc); } - if (memc_sess->memc_sess) { - if (!memc_sess->is_persistent) { -#ifdef HAVE_MEMCACHED_SASL - if (MEMC_G(sess_sasl_data)) { - memcached_destroy_sasl_auth_data(memc_sess->memc_sess); - } -#endif - memcached_free(memc_sess->memc_sess); - efree(memc_sess); - } - PS_SET_MOD_DATA(NULL); + + if (!user_data->is_persistent) { + s_destroy_mod_data(memc); } + PS_SET_MOD_DATA(NULL); return SUCCESS; } @@ -306,35 +380,27 @@ PS_READ_FUNC(memcached) { char *payload = NULL; size_t payload_len = 0; - int key_len = key->len; uint32_t flags = 0; memcached_return status; - memcached_sess *memc_sess = PS_GET_MOD_DATA(); - size_t key_length; + memcached_st *memc = PS_GET_MOD_DATA(); - if (!memc_sess) { + if (!memc) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session is not allocated, check session.save_path value"); return FAILURE; } - key_length = strlen(MEMC_G(sess_prefix)) + key_len + 5; // prefix + "lock." - if (!key_length || key_length >= MEMCACHED_MAX_KEY) { - php_error_docref(NULL, E_WARNING, "The session id is too long or contains illegal characters"); - return FAILURE; - } - - if (MEMC_G(sess_locking_enabled)) { - if (php_memc_sess_lock(memc_sess->memc_sess, key->val) < 0) { + if (MEMC_SESS_INI(lock_enabled)) { + if (!s_lock_session(memc, key)) { php_error_docref(NULL, E_WARNING, "Unable to clear session lock record"); return FAILURE; } } - payload = memcached_get(memc_sess->memc_sess, key->val, key_len, &payload_len, &flags, &status); + payload = memcached_get(memc, key->val, key->len, &payload_len, &flags, &status); if (status == MEMCACHED_SUCCESS) { - *val = zend_string_init(payload, payload_len, 1); - free(payload); + *val = zend_string_init(payload, payload_len, 0); + efree(payload); return SUCCESS; } else if (status == MEMCACHED_NOTFOUND) { *val = ZSTR_EMPTY_ALLOC(); @@ -346,59 +412,53 @@ PS_READ_FUNC(memcached) PS_WRITE_FUNC(memcached) { - int key_len = key->len; - time_t expiration = 0; - long write_try_attempts = 1; - memcached_return status; - memcached_sess *memc_sess = PS_GET_MOD_DATA(); + zend_long retries = 1; + memcached_st *memc = PS_GET_MOD_DATA(); size_t key_length; + time_t expiration; - if (!memc_sess) { + if (!memc) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session is not allocated, check session.save_path value"); return FAILURE; } - key_length = strlen(MEMC_G(sess_prefix)) + key_len + 5; // prefix + "lock." - if (!key_length || key_length >= MEMCACHED_MAX_KEY) { - php_error_docref(NULL, E_WARNING, "The session id is too long or contains illegal characters"); - return FAILURE; - } + /* Set the number of write retry attempts to the number of replicas times the number of attempts to remove a server plus the initial write */ + if (MEMC_SESS_INI(remove_failed_servers_enabled)) { + zend_long replicas, failure_limit; - if (maxlifetime > 0) { - expiration = maxlifetime; - } + replicas = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS); + failure_limit = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT); - /* Set the number of write retry attempts to the number of replicas times the number of attempts to remove a server plus the initial write */ - if (MEMC_G(sess_remove_failed_enabled)) { - write_try_attempts = 1 + MEMC_G(sess_number_of_replicas) * ( memcached_behavior_get(memc_sess->memc_sess, MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT) + 1); + retries = 1 + replicas * (failure_limit + 1); } + expiration = time(NULL) + maxlifetime; + do { - status = memcached_set(memc_sess->memc_sess, key->val, key_len, val->val, val->len, expiration, 0); - if (status == MEMCACHED_SUCCESS) { + if (memcached_set(memc, key->val, key->len, val->val, val->len, expiration, 0) == MEMCACHED_SUCCESS) { return SUCCESS; - } else { - write_try_attempts--; } - } while (write_try_attempts > 0); + } while (--retries > 0); return FAILURE; } PS_DESTROY_FUNC(memcached) { - memcached_sess *memc_sess = PS_GET_MOD_DATA(); + php_memcached_user_data *user_data; + memcached_st *memc = PS_GET_MOD_DATA(); - if (!memc_sess) { + if (!memc) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session is not allocated, check session.save_path value"); return FAILURE; } - memcached_delete(memc_sess->memc_sess, key->val, key->len, 0); - if (MEMC_G(sess_locking_enabled)) { - php_memc_sess_unlock(memc_sess->memc_sess); - } + memcached_delete(memc, key->val, key->len, 0); + user_data = memcached_get_user_data(memc); + if (user_data->is_locked) { + s_unlock_session(memc); + } return SUCCESS; } @@ -410,34 +470,31 @@ PS_GC_FUNC(memcached) PS_CREATE_SID_FUNC(memcached) { zend_string *sid; - int retries = 3; - memcached_sess *memc_sess = PS_GET_MOD_DATA(); - time_t expiration = PS(gc_maxlifetime); + memcached_st *memc = PS_GET_MOD_DATA(); - if (!memc_sess) { - return NULL; + if (!memc) { + sid = php_session_create_id(NULL); } + else { + int retries = 3; + while (retries-- > 0) { + sid = php_session_create_id((void **) &memc); - while (retries-- > 0) { - sid = php_session_create_id((void**)&memc_sess); - - if (sid) { - if (memcached_add(memc_sess->memc_sess, sid->val, sid->len, "0", 0, expiration, 0) == MEMCACHED_SUCCESS) { - return sid; - } - else { - zend_string_release(sid); + if (memcached_add (memc, sid->val, sid->len, NULL, 0, s_lock_expiration(), 0) == MEMCACHED_SUCCESS) { + break; } + zend_string_release(sid); + sid = NULL; } } - return NULL; + return sid; } PS_VALIDATE_SID_FUNC(memcached) { - memcached_sess *memc_sess = PS_GET_MOD_DATA(); + memcached_st *memc = PS_GET_MOD_DATA(); - if (php_memcached_exist(memc_sess->memc_sess, key) == MEMCACHED_SUCCESS) { + if (php_memcached_exist(memc, key) == MEMCACHED_SUCCESS) { return SUCCESS; } else { return FAILURE; @@ -446,13 +503,10 @@ PS_VALIDATE_SID_FUNC(memcached) PS_UPDATE_TIMESTAMP_FUNC(memcached) { - memcached_sess *memc_sess = PS_GET_MOD_DATA(); - time_t expiration = 0; + memcached_st *memc = PS_GET_MOD_DATA(); + time_t expiration = time(NULL) + maxlifetime; - if (maxlifetime > 0) { - expiration = maxlifetime; - } - if (memcached_touch(memc_sess->memc_sess, key->val, key->len, expiration) == MEMCACHED_FAILURE) { + if (memcached_touch(memc, key->val, key->len, expiration) == MEMCACHED_FAILURE) { return FAILURE; } return SUCCESS; diff --git a/php_memcached_session.h b/php_memcached_session.h index 4118362f..13ce363c 100644 --- a/php_memcached_session.h +++ b/php_memcached_session.h @@ -36,4 +36,7 @@ PS_CREATE_SID_FUNC(memcached); PS_VALIDATE_SID_FUNC(memcached); PS_UPDATE_TIMESTAMP_FUNC(memcached); +/* Called from php_memcached.c */ +int php_memc_session_minit(int module_number); + #endif /* PHP_MEMCACHED_SESSION_H */ diff --git a/tests/cachecallback.phpt b/tests/cachecallback.phpt index 9fe8f4f8..31a736b7 100644 --- a/tests/cachecallback.phpt +++ b/tests/cachecallback.phpt @@ -13,6 +13,10 @@ $first_key = uniqid ('cache_test_'); $second_key = uniqid ('cache_test_'); $third_key = uniqid ('cache_test_'); +$m->delete($first_key); +$m->delete($second_key); +$m->delete($third_key); + var_dump ( $m->get ($first_key, function (Memcached $memc, $key, &$value, &$expiration) { $value = "hello"; diff --git a/tests/cas.phpt b/tests/cas.phpt index e9990798..c1c1752f 100644 --- a/tests/cas.phpt +++ b/tests/cas.phpt @@ -8,47 +8,12 @@ include dirname (__FILE__) . '/config.inc'; $m = memc_get_instance (); $m->delete('cas_test'); -$cas_token = null; +$cas_token = 0; -$m->set('cas_test', 10); -$v = $m->get('cas_test', null, $cas_token); - -if (is_null($cas_token)) { - echo "Null cas token for key: cas_test value: 10\n"; - return; -} - -$v = $m->cas($cas_token, 'cas_test', 11); -if (!$v) { - echo "Error setting key: cas_test value: 11 with CAS: $cas_token\n"; - return; -} - -$v = $m->get('cas_test'); - -if ($v !== 11) { - echo "Wanted cas_test to be 11, value is: "; - var_dump($v); -} - -$v = $m->get('cas_test', null, 2); -if ($v != 11) { - echo "Failed to get the value with \$cas_token passed by value (2)\n"; - return; -} - -$v = $m->get('cas_test', null, null); -if ($v != 11) { - echo "Failed to get the value with \$cas_token passed by value (null)\n"; - return; -} - -$v = $m->get('cas_test', null, $data = array(2, 4)); -if ($v != 11 || $data !== array(2, 4)) { - echo "Failed to get the value with \$cas_token passed by value (\$data = array(2, 4))\n"; - return; -} +$m->set('cas_test', 'hello'); +$cas_token = $m->get('cas_test', null, Memcached::GET_EXTENDED)['cas']; +$v = $m->cas($cas_token, 'cas_test', 0); echo "OK\n"; ?> --EXPECT-- diff --git a/tests/cas_multi.phpt b/tests/cas_multi.phpt index 240ecadd..499742be 100644 --- a/tests/cas_multi.phpt +++ b/tests/cas_multi.phpt @@ -16,25 +16,22 @@ foreach ($data as $key => $v) { $m->delete($key); } -$cas_tokens = array(); $m->setMulti($data, 10); -$actual = $m->getMulti(array_keys($data), $cas_tokens); +$actual = $m->getMulti(array_keys($data), Memcached::GET_EXTENDED); -foreach ($data as $key => $v) { - if (is_null($cas_tokens[$key])) { +foreach ($actual as $key => $v) { + if (is_null($v['cas'])) { echo "missing cas token(s)\n"; echo "data: "; var_dump($data); echo "actual data: "; var_dump($actual); - echo "cas tokens: "; - var_dump($cas_tokens); return; } - $v = $m->cas($cas_tokens[$key], $key, 11); + $v = $m->cas($v['cas'], $key, 11); if (!$v) { - echo "Error setting key: $key value: 11 with CAS: ", $cas_tokens[$key], "\n"; + echo "Error setting key: $key value: 11 with CAS: ", $v['cas'], "\n"; return; } $v = $m->get($key); @@ -54,24 +51,6 @@ if (array_keys($actual) !== array_keys($data)) { return; } -$actual = $m->getMulti(array_keys($data), 2); -if (array_keys($actual) !== array_keys($data)) { - echo "Failed to getMulti \$cas_token passed by value (2)\n"; - return; -} - -$actual = $m->getMulti(array_keys($data), null); -if (array_keys($actual) !== array_keys($data)) { - echo "Failed to getMulti \$cas_token passed by value (null)\n"; - return; -} - -$actual = $m->getMulti(array_keys($data), $cas_tokens = array(2, 4)); -if (array_keys($actual) !== array_keys($data) || $cas_tokens !== array(2, 4)) { - echo "Failed to getMulti \$cas_token passed by value (\$cas_tokens = array(2, 4))\n"; - return; -} - echo "OK\n"; ?> diff --git a/tests/multi_order.phpt b/tests/multi_order.phpt index 4fd5f5b4..876ddc66 100644 --- a/tests/multi_order.phpt +++ b/tests/multi_order.phpt @@ -21,10 +21,9 @@ foreach ($data as $k => $v) { $m->set($k, $v, 3600); } -$null = null; $keys = array_keys($data); $keys[] = 'zoo'; -$got = $m->getMulti($keys, $null, Memcached::GET_PRESERVE_ORDER); +$got = $m->getMulti($keys, Memcached::GET_PRESERVE_ORDER); foreach ($got as $k => $v) { echo "$k $v\n"; diff --git a/tests/no-not-found.phpt b/tests/no-not-found.phpt index de96d3e4..06ae85e9 100644 --- a/tests/no-not-found.phpt +++ b/tests/no-not-found.phpt @@ -11,8 +11,7 @@ $memcached->addServer('localhost', 5555); // Server should not exist $result = $memcached->get('foo_not_exists'); var_dump ($result === Memcached::GET_ERROR_RETURN_VALUE); -$cas = 7; -$result = $memcached->get('foo_not_exists', null, $cas); +$result = $memcached->get('foo_not_exists'); var_dump ($result === Memcached::GET_ERROR_RETURN_VALUE); echo "OK\n"; diff --git a/tests/rescode.phpt b/tests/rescode.phpt index fbda4f78..5b835d44 100644 --- a/tests/rescode.phpt +++ b/tests/rescode.phpt @@ -23,6 +23,7 @@ $m->delete('bar_foo'); echo $m->getResultCode(), "\n"; echo $m->getResultMessage(), "\n"; +$m->set ('asdf_a', 'aa'); $m->getMulti(array('asdf_a', 'jkhjkhjkb', 'nbahsdgc')); echo $m->getResultMessage(), "\n"; $code = $m->getResultCode(); diff --git a/tests/set_large.phpt b/tests/set_large.phpt index d9353a8e..bf1098ef 100644 --- a/tests/set_large.phpt +++ b/tests/set_large.phpt @@ -9,8 +9,9 @@ $m = memc_get_instance (); $key = 'foobarbazDEADC0DE'; $value = str_repeat("foo bar", 1024 * 1024); -$m->set($key, $value, 360); +var_dump($m->set($key, $value, 360)); var_dump($m->get($key) === $value); ?> --EXPECT-- bool(true) +bool(true) diff --git a/tests/user-flags.phpt b/tests/user-flags.phpt index 137ff1e8..7b02ea2d 100644 --- a/tests/user-flags.phpt +++ b/tests/user-flags.phpt @@ -16,6 +16,10 @@ function check_flags ($flags, $expected_flags) echo "Flags OK" . PHP_EOL; } +function get_flags($m, $key) { + return $m->get($key, null, Memcached::GET_EXTENDED)['flags']; +} + define ('FLAG_1', 1); define ('FLAG_2', 2); define ('FLAG_4', 4); @@ -30,26 +34,26 @@ $key = uniqid ('udf_test_'); // Set with flags off $m->set ($key, '1', 10); -$m->get($key); -var_dump($m->getLastUserFlags()); +$v = $m->get($key, null, Memcached::GET_EXTENDED); +var_dump($v); // Set flags on $m->setOption(Memcached::OPT_USER_FLAGS, FLAG_1); $m->set ($key, '1', 10); $m->get($key); -check_flags($m->getLastUserFlags()[$key], array(FLAG_1)); +check_flags(get_flags($m, $key), array(FLAG_1)); // Multiple flags $m->setOption(Memcached::OPT_USER_FLAGS, FLAG_1 | FLAG_2 | FLAG_4); $m->set ($key, '1', 10); $m->get($key); -check_flags($m->getLastUserFlags()[$key], array(FLAG_1, FLAG_2, FLAG_4)); +check_flags(get_flags($m, $key), array(FLAG_1, FLAG_2, FLAG_4)); // Even more flags $m->setOption(Memcached::OPT_USER_FLAGS, FLAG_1 | FLAG_2 | FLAG_4 | FLAG_32 | FLAG_64); $m->set ($key, '1', 10); $m->get($key); -check_flags($m->getLastUserFlags()[$key], array(FLAG_1, FLAG_2, FLAG_4, FLAG_32, FLAG_64)); +check_flags(get_flags($m, $key), array(FLAG_1, FLAG_2, FLAG_4, FLAG_32, FLAG_64)); // User flags with get multi $values = array( @@ -61,10 +65,10 @@ $values = array( $m->setOption(Memcached::OPT_USER_FLAGS, FLAG_2 | FLAG_4); $m->setMulti($values); $m->getMulti(array_keys($values)); -$flags = $m->getLastUserFlags(); +$flags = $m->getMulti(array_keys($values), Memcached::GET_EXTENDED); foreach (array_keys($values) as $key) { - check_flags($flags[$key], array(FLAG_2, FLAG_4)); + check_flags($flags[$key]['flags'], array(FLAG_2, FLAG_4)); } // User flags with compression on @@ -74,7 +78,7 @@ $m->setOption(Memcached::OPT_COMPRESSION_TYPE, Memcached::COMPRESSION_FASTLZ); $m->set ($key, '1', 10); $m->get($key); -check_flags($m->getLastUserFlags()[$key], array(FLAG_1, FLAG_2, FLAG_4)); +check_flags(get_flags($m, $key), array(FLAG_1, FLAG_2, FLAG_4)); // Too large flags @@ -83,8 +87,12 @@ $m->setOption(Memcached::OPT_USER_FLAGS, FLAG_TOO_LARGE); echo "DONE TEST\n"; ?> --EXPECTF-- -array(1) { - ["udf_test_%s"]=> +array(3) { + ["value"]=> + string(1) "1" + ["cas"]=> + int(%d) + ["flags"]=> int(0) } Flags OK From c15d792ec3b646df6fa06c39328441f107120e9e Mon Sep 17 00:00:00 2001 From: Mikko Date: Sat, 30 Jan 2016 11:41:57 +0000 Subject: [PATCH 053/104] Clean up session code, start on the whole i_obj/m_obj confusion --- php_memcached.c | 255 ++++++++++++++++------------------ php_memcached_session.c | 49 ++++--- tests/callback_exception.phpt | 3 +- tests/cas.phpt | 5 +- 4 files changed, 155 insertions(+), 157 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index 23e9bde3..e91a5600 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -122,67 +122,8 @@ php_memc_t* i_obj = NULL; \ struct memc_obj* m_obj = NULL; -#ifndef DVAL_TO_LVAL -#ifdef _WIN64 -# define DVAL_TO_LVAL(d, l) \ - if ((d) > LONG_MAX) { \ - (l) = (long)(unsigned long)(__int64) (d); \ - } else { \ - (l) = (long) (d); \ - } -#else -# define DVAL_TO_LVAL(d, l) \ - if ((d) > LONG_MAX) { \ - (l) = (unsigned long) (d); \ - } else { \ - (l) = (long) (d); \ - } -#endif -#endif - #define RETURN_FROM_GET RETURN_FALSE -typedef memcached_return (*memc_store_fn)( - memcached_st *, - const char *key, size_t key_len, - const char *payload, size_t payload_len, - time_t expiration, uint32_t flags); - -typedef memcached_return (*memc_store_by_key_fn)( - memcached_st *, - const char *server_key, size_t server_key_len, - const char *key, size_t key_len, - const char *payload, size_t payload_len, - time_t expiration, uint32_t flags); - -static memc_store_fn php_memc_store_funcs[] = { - &memcached_set, - &memcached_add, - &memcached_replace, - &memcached_prepend, - &memcached_append -}; - -void s_call_store_func(int op, memcached_st *memc, const char *key, size_t key_len, const char *payload, size_t payload_len, time_t expiration, uint32_t flags) -{ - (*php_memc_store_funcs[op])(memc, key, key_len,payload, payload_len, expiration, flags); -} - - -static memc_store_by_key_fn php_memc_store_by_keys_funcs[] = { - &memcached_set_by_key, - &memcached_add_by_key, - &memcached_replace_by_key, - &memcached_prepend_by_key, - &memcached_append_by_key -}; - -void s_call_store_by_key_func(int op, memcached_st *memc, const char *server_key, size_t server_key_len, const char *key, size_t key_len, const char *payload, size_t payload_len, time_t expiration, uint32_t flags) -{ - (*php_memc_store_by_keys_funcs[op])(memc, server_key, server_key_len, key, key_len,payload, payload_len, expiration, flags); -} - - /**************************************** Structures and definitions ****************************************/ @@ -314,10 +255,10 @@ static PHP_INI_MH(OnUpdateSerializer) } #define MEMC_INI_ENTRY(key, default_value, update_fn, gkey) \ - STD_PHP_INI_ENTRY("memcached.##key", default_value, PHP_INI_ALL, update_fn, memc_ini.gkey, zend_php_memcached_globals, php_memcached_globals) + STD_PHP_INI_ENTRY("memcached."key, default_value, PHP_INI_ALL, update_fn, memc_ini.gkey, zend_php_memcached_globals, php_memcached_globals) #define MEMC_SESSION_INI_ENTRY(key, default_value, update_fn, gkey) \ - STD_PHP_INI_ENTRY("memcached.session.##key", default_value, PHP_INI_ALL, update_fn, session_ini.gkey, zend_php_memcached_globals, php_memcached_globals) + STD_PHP_INI_ENTRY("memcached.session."key, default_value, PHP_INI_ALL, update_fn, session_ini.gkey, zend_php_memcached_globals, php_memcached_globals) /* {{{ INI entries */ @@ -349,7 +290,6 @@ PHP_INI_BEGIN() MEMC_INI_ENTRY("serializer", SERIALIZER_DEFAULT_NAME, OnUpdateSerializer, serializer_name) MEMC_INI_ENTRY("use_sasl", "0", OnUpdateBool, sasl_enabled) MEMC_INI_ENTRY("store_retry_count", "2", OnUpdateLong, store_retry_count) - PHP_INI_END() /* }}} */ @@ -472,7 +412,6 @@ static PHP_METHOD(Memcached, __construct) struct memc_obj *m_obj = NULL; zend_string *persistent_id = NULL; zend_string *conn_str = NULL; - zend_bool is_persistent = 0; zend_string *plist_key = NULL; zend_fcall_info fci = {0}; zend_fcall_info_cache fci_cache; @@ -483,102 +422,103 @@ static PHP_METHOD(Memcached, __construct) i_obj = Z_MEMC_OBJ_P(object); i_obj->is_pristine = 0; + i_obj->is_persistent = 0; if (persistent_id && persistent_id->len) { zend_resource *le; - is_persistent = 1; plist_key = zend_string_alloc(sizeof("memcached:id=") + persistent_id->len - 1, 0); snprintf(plist_key->val, plist_key->len + 1, "memcached:id=%s", persistent_id->val); + if ((le = zend_hash_find_ptr(&EG(persistent_list), plist_key)) != NULL) { if (le->type == php_memc_list_entry()) { m_obj = (struct memc_obj *) le->ptr; + + i_obj->obj = m_obj; + i_obj->is_persistent = 1; + zend_string_release (plist_key); + return; } } - i_obj->obj = m_obj; + i_obj->is_persistent = 1; } - i_obj->is_persistent = is_persistent; + m_obj = pecalloc(1, sizeof(*m_obj), i_obj->is_persistent); + if (m_obj == NULL) { + if (plist_key) { + zend_string_release(plist_key); + } + php_error_docref(NULL, E_ERROR, "out of memory: cannot allocate handle"); + /* not reached */ + } - if (!m_obj) { - m_obj = pecalloc(1, sizeof(*m_obj), is_persistent); - if (m_obj == NULL) { + if (conn_str) { + m_obj->memc = php_memc_create_str(conn_str->val, conn_str->len); + if (!m_obj->memc) { + char error_buffer[1024]; if (plist_key) { zend_string_release(plist_key); } - php_error_docref(NULL, E_ERROR, "out of memory: cannot allocate handle"); - /* not reached */ - } - - if (conn_str) { - m_obj->memc = php_memc_create_str(conn_str->val, conn_str->len); - if (!m_obj->memc) { - char error_buffer[1024]; - if (plist_key) { - zend_string_release(plist_key); - } #ifdef HAVE_LIBMEMCACHED_CHECK_CONFIGURATION - if (libmemcached_check_configuration(conn_str->val, conn_str->len, error_buffer, sizeof(error_buffer)) != MEMCACHED_SUCCESS) { - php_error_docref(NULL, E_ERROR, "configuration error %s", error_buffer); - } else { - php_error_docref(NULL, E_ERROR, "could not allocate libmemcached structure"); - } -#else + if (libmemcached_check_configuration(conn_str->val, conn_str->len, error_buffer, sizeof(error_buffer)) != MEMCACHED_SUCCESS) { + php_error_docref(NULL, E_ERROR, "configuration error %s", error_buffer); + } else { php_error_docref(NULL, E_ERROR, "could not allocate libmemcached structure"); -#endif - /* not reached */ } - } else { - m_obj->memc = memcached_create(NULL); - if (m_obj->memc == NULL) { - if (plist_key) { - zend_string_release(plist_key); - } - php_error_docref(NULL, E_ERROR, "could not allocate libmemcached structure"); - /* not reached */ +#else + php_error_docref(NULL, E_ERROR, "could not allocate libmemcached structure"); +#endif + /* not reached */ + } + } else { + m_obj->memc = memcached_create(NULL); + if (m_obj->memc == NULL) { + if (plist_key) { + zend_string_release(plist_key); } + php_error_docref(NULL, E_ERROR, "could not allocate libmemcached structure"); + /* not reached */ } + } - m_obj->serializer = MEMC_G(serializer); - m_obj->compression_type = MEMC_G(compression_type_real); - m_obj->compression = 1; - m_obj->store_retry_count = MEMC_G(store_retry_count); - - m_obj->set_udf_flags = -1; - - i_obj->obj = m_obj; - i_obj->is_pristine = 1; + m_obj->serializer = MEMC_G(serializer); + m_obj->compression_type = MEMC_G(compression_type_real); + m_obj->compression = 1; + m_obj->store_retry_count = MEMC_G(store_retry_count); + m_obj->set_udf_flags = -1; - if (fci.size) { /* will be 0 when not available */ - if (!php_memcached_on_new_callback(object, &fci, &fci_cache, persistent_id) || EG(exception)) { - /* error calling or exception thrown from callback */ - if (plist_key) { - zend_string_release(plist_key); - } + i_obj->obj = m_obj; + i_obj->is_pristine = 1; - i_obj->obj = NULL; - if (is_persistent) { - php_memc_destroy(m_obj, is_persistent); - } + if (fci.size) { /* will be 0 when not available */ + if (!php_memcached_on_new_callback(object, &fci, &fci_cache, persistent_id) || EG(exception)) { + /* error calling or exception thrown from callback */ + if (plist_key) { + zend_string_release(plist_key); + } - return; + i_obj->obj = NULL; + if (i_obj->is_persistent) { + php_memc_destroy(m_obj, i_obj->is_persistent); } + + return; } + } - if (is_persistent) { - zend_resource le; + if (i_obj->is_persistent) { + zend_resource le; - le.type = php_memc_list_entry(); - le.ptr = m_obj; - GC_REFCOUNT(&le) = 1; - /* plist_key is not a persistent allocated key, thus we use str_update here */ - if (zend_hash_str_update_mem(&EG(persistent_list), plist_key->val, plist_key->len, &le, sizeof(le)) == NULL) { - if (plist_key) { - zend_string_release(plist_key); - } - php_error_docref(NULL, E_ERROR, "could not register persistent entry"); - /* not reached */ + le.type = php_memc_list_entry(); + le.ptr = m_obj; + GC_REFCOUNT(&le) = 1; + /* plist_key is not a persistent allocated key, thus we use str_update here */ + if (zend_hash_str_update_mem(&EG(persistent_list), plist_key->val, plist_key->len, &le, sizeof(le)) == NULL) { + if (plist_key) { + zend_string_release(plist_key); } + php_error_docref(NULL, E_ERROR, "could not register persistent entry"); + /* not reached */ } } @@ -593,7 +533,12 @@ void s_uint64_to_zval (zval *target, uint64_t value) { if (value >= LONG_MAX) { char *buffer; +#ifdef PRIu64 spprintf (&buffer, 0, "%" PRIu64, value); +#else + /* Best effort */ + spprintf (&buffer, 0, "%llu", value); +#endif ZVAL_STRING (target, buffer); efree(buffer); } @@ -602,6 +547,41 @@ void s_uint64_to_zval (zval *target, uint64_t value) } } +static +uint64_t s_zval_to_uint64 (zval *cas) +{ + switch (Z_TYPE_P (cas)) { + case IS_LONG: + return (uint64_t) zval_get_long (cas); + break; + + case IS_DOUBLE: + if (Z_DVAL_P (cas) < 0.0) + return 0; + + return (uint64_t) zval_get_double (cas); + break; + + case IS_STRING: + { + uint64_t val; + char *end; + + errno = 0; + val = (uint64_t) strtoull (Z_STRVAL_P (cas), &end, 0); + + if (*end || (errno == ERANGE && val == UINT64_MAX) || (errno != 0 && val == 0)) { + php_error_docref(NULL, E_ERROR, "Failed to unmarshall cas token"); + return 0; + } + return val; + } + break; + } + return 0; +} + + typedef struct { size_t num_valid_keys; @@ -674,10 +654,7 @@ memcached_return s_memcached_get_multi(memcached_st *memc, HashTable *hash_keys, { php_memcached_keys keys = { 0 }; zval values; - memcached_return rc, status = MEMCACHED_SUCCESS; - - size_t num_keys; uint64_t orig_cas_flag; memcached_result_st result; @@ -860,7 +837,6 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke { zval *keys = NULL; zend_string *server_key = NULL; - zend_bool extended_results = 0; memcached_return rc; zend_long flags = 0; MEMC_METHOD_INIT_VARS; @@ -1559,7 +1535,7 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool /* {{{ -- php_memc_cas_impl */ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { - double cas_d; + zval *zv_cas; uint64_t cas; zend_string *key; zend_string *server_key = NULL; @@ -1571,12 +1547,12 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) MEMC_METHOD_INIT_VARS; if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "dSSz|ll", &cas_d, &server_key, &key, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zSSz|ll", &zv_cas, &server_key, &key, &value, &expiration) == FAILURE) { return; } } else { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "dSz|ll", &cas_d, &key, &value, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zSz|ll", &zv_cas, &key, &value, &expiration) == FAILURE) { return; } @@ -1590,7 +1566,7 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) RETURN_FALSE; } - DVAL_TO_LVAL(cas_d, cas); + cas = s_zval_to_uint64(zv_cas); if (m_obj->compression) { MEMC_VAL_SET_FLAG(flags, MEMC_VAL_COMPRESSED); @@ -1615,6 +1591,7 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) } else { status = memcached_cas(m_obj->memc, key->val, key->len, payload->val, payload->len, expiration, flags, cas); } + zend_string_release(payload); if (php_memc_handle_error(i_obj, status) < 0) { RETURN_FALSE; @@ -4122,7 +4099,8 @@ PHP_GINIT_FUNCTION(php_memcached) } zend_module_entry memcached_module_entry = { - STANDARD_MODULE_HEADER, + STANDARD_MODULE_HEADER_EX, NULL, + memcached_deps, "memcached", NULL, PHP_MINIT(memcached), @@ -4139,6 +4117,7 @@ zend_module_entry memcached_module_entry = { }; /* }}} */ + /* {{{ php_memc_register_constants */ static void php_memc_register_constants(INIT_FUNC_ARGS) { @@ -4409,12 +4388,12 @@ PHP_MINIT_FUNCTION(memcached) */ php_memc_register_constants(INIT_FUNC_ARGS_PASSTHRU); + REGISTER_INI_ENTRIES(); #ifdef HAVE_MEMCACHED_SESSION php_memc_session_minit(module_number); #endif - REGISTER_INI_ENTRIES(); #if HAVE_MEMCACHED_SASL if (MEMC_G(sasl_enabled)) { if (sasl_client_init(NULL) != SASL_OK) { diff --git a/php_memcached_session.c b/php_memcached_session.c index 8c6454a1..1a398ab7 100644 --- a/php_memcached_session.c +++ b/php_memcached_session.c @@ -95,8 +95,6 @@ int php_memc_session_minit(int module_number) static time_t s_lock_expiration() { - zend_long max_execution_time; - if (MEMC_SESS_INI(lock_expiration) > 0) { return time(NULL) + MEMC_SESS_INI(lock_expiration); } @@ -109,9 +107,19 @@ time_t s_lock_expiration() return 0; } +static +time_t s_session_expiration(zend_long maxlifetime) +{ + if (maxlifetime > 0) { + return time(NULL) + maxlifetime; + } + return 0; +} + static zend_bool s_lock_session(memcached_st *memc, zend_string *sid) { + memcached_return rc; char *lock_key; size_t lock_key_len; time_t expiration; @@ -125,8 +133,7 @@ zend_bool s_lock_session(memcached_st *memc, zend_string *sid) retries = MEMC_SESS_INI(lock_retries); do { - memcached_return rc = - memcached_add(memc, lock_key, lock_key_len, "1", sizeof ("1") - 1, expiration, 0); + rc = memcached_add(memc, lock_key, lock_key_len, "1", sizeof ("1") - 1, expiration, 0); switch (rc) { @@ -137,8 +144,10 @@ zend_bool s_lock_session(memcached_st *memc, zend_string *sid) case MEMCACHED_NOTSTORED: case MEMCACHED_DATA_EXISTS: - usleep(wait_time * 1000); - wait_time = MIN(MEMC_SESS_INI(lock_wait_max), wait_time * 2); + if (retries > 0) { + usleep(wait_time * 1000); + wait_time = MIN(MEMC_SESS_INI(lock_wait_max), wait_time * 2); + } break; default: @@ -164,13 +173,13 @@ void s_unlock_session(memcached_st *memc) } static -zend_bool s_configure_from_ini_values(memcached_st *memc) +zend_bool s_configure_from_ini_values(memcached_st *memc, zend_bool silent) { memcached_return rc; #define check_set_behavior(behavior, value) \ if ((rc = memcached_behavior_set(memc, (behavior), (value))) != MEMCACHED_SUCCESS) { \ - php_error_docref(NULL, E_WARNING, "failed to initialise session memcached configuration: %s", memcached_strerror(memc, rc)); \ + if (!silent) { php_error_docref(NULL, E_WARNING, "failed to initialise session memcached configuration: %s", memcached_strerror(memc, rc)); } \ return 0; \ } @@ -280,7 +289,7 @@ memcached_st *s_init_mod_data (const memcached_server_list_st servers, zend_bool memcached_set_memory_allocators(memc, s_pemalloc_fn, s_pefree_fn, s_perealloc_fn, s_pecalloc_fn, NULL); - user_data = pecalloc(1, sizeof(php_memcached_user_data), is_persistent); + user_data = pecalloc(1, sizeof(php_memcached_user_data), is_persistent); user_data->is_persistent = is_persistent; user_data->has_sasl_data = 0; user_data->lock_key = NULL; @@ -316,7 +325,7 @@ PS_OPEN_FUNC(memcached) if (le_p->type == s_memc_sess_list_entry()) { memc = (memcached_st *) le_p->ptr; - if (!s_configure_from_ini_values(memc)) { + if (!s_configure_from_ini_values(memc, 1)) { // Remove existing plist entry zend_hash_str_del(&EG(persistent_list), plist_key, plist_key_len); memc = NULL; @@ -333,6 +342,14 @@ PS_OPEN_FUNC(memcached) memc = s_init_mod_data(servers, MEMC_SESS_INI(persistent_enabled)); memcached_server_list_free(servers); + if (!s_configure_from_ini_values(memc, 0)) { + if (plist_key) { + efree(plist_key); + } + PS_SET_MOD_DATA(NULL); + return FAILURE; + } + if (plist_key) { zend_resource le; @@ -358,7 +375,7 @@ PS_CLOSE_FUNC(memcached) php_memcached_user_data *user_data; if (!memc) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session is not allocated, check session.save_path value"); + php_error_docref(NULL, E_WARNING, "Session is not allocated, check session.save_path value"); return FAILURE; } @@ -385,7 +402,7 @@ PS_READ_FUNC(memcached) memcached_st *memc = PS_GET_MOD_DATA(); if (!memc) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session is not allocated, check session.save_path value"); + php_error_docref(NULL, E_WARNING, "Session is not allocated, check session.save_path value"); return FAILURE; } @@ -414,8 +431,7 @@ PS_WRITE_FUNC(memcached) { zend_long retries = 1; memcached_st *memc = PS_GET_MOD_DATA(); - size_t key_length; - time_t expiration; + time_t expiration = s_session_expiration(maxlifetime); if (!memc) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session is not allocated, check session.save_path value"); @@ -432,8 +448,6 @@ PS_WRITE_FUNC(memcached) retries = 1 + replicas * (failure_limit + 1); } - expiration = time(NULL) + maxlifetime; - do { if (memcached_set(memc, key->val, key->len, val->val, val->len, expiration, 0) == MEMCACHED_SUCCESS) { return SUCCESS; @@ -504,7 +518,7 @@ PS_VALIDATE_SID_FUNC(memcached) PS_UPDATE_TIMESTAMP_FUNC(memcached) { memcached_st *memc = PS_GET_MOD_DATA(); - time_t expiration = time(NULL) + maxlifetime; + time_t expiration = s_session_expiration(maxlifetime); if (memcached_touch(memc, key->val, key->len, expiration) == MEMCACHED_FAILURE) { return FAILURE; @@ -512,3 +526,4 @@ PS_UPDATE_TIMESTAMP_FUNC(memcached) return SUCCESS; } /* }}} */ + diff --git a/tests/callback_exception.phpt b/tests/callback_exception.phpt index 8f71d5f8..fa149077 100644 --- a/tests/callback_exception.phpt +++ b/tests/callback_exception.phpt @@ -37,7 +37,8 @@ try { } try { - + $m = new Memcached(null, 'throw_something'); + echo "fail\n"; } catch (Exception $e) { echo "fail\n"; } diff --git a/tests/cas.phpt b/tests/cas.phpt index c1c1752f..60090c97 100644 --- a/tests/cas.phpt +++ b/tests/cas.phpt @@ -8,12 +8,15 @@ include dirname (__FILE__) . '/config.inc'; $m = memc_get_instance (); $m->delete('cas_test'); -$cas_token = 0; $m->set('cas_test', 'hello'); $cas_token = $m->get('cas_test', null, Memcached::GET_EXTENDED)['cas']; $v = $m->cas($cas_token, 'cas_test', 0); +if ($v != true) { + echo "CAS failed"; +} + echo "OK\n"; ?> --EXPECT-- From bdd0911a9bdde9c3f1f4ab14e69055dbd5b643ad Mon Sep 17 00:00:00 2001 From: Mikko Date: Sun, 31 Jan 2016 16:07:48 +0000 Subject: [PATCH 054/104] Update to a simpler object structure, make session config match old setting names, key validation removed etc --- php_memcached.c | 1026 +++++++++++++----------- php_memcached_private.h | 3 + php_memcached_session.c | 17 + tests/bug_16084.phpt | 18 +- tests/callback_exception.phpt | 3 +- tests/getserverlist.phpt | 21 +- tests/invoke_callback.phpt | 5 +- tests/keys.phpt | 1 + tests/session_badconf_emptyprefix.phpt | 17 +- tests/session_badconf_prefix.phpt | 21 +- tests/session_badconf_servers.phpt | 4 - tests/session_basic.phpt | 6 +- tests/session_basic2.phpt | 6 +- tests/session_basic3.phpt | 12 +- 14 files changed, 631 insertions(+), 529 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index e91a5600..1dbe0bab 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -55,6 +55,8 @@ #define MEMC_G(v) (php_memcached_globals.memc_ini.v) #endif +#include + /**************************************** Custom options @@ -117,10 +119,7 @@ /**************************************** Helper macros ****************************************/ -#define MEMC_METHOD_INIT_VARS \ - zval* object = getThis(); \ - php_memc_t* i_obj = NULL; \ - struct memc_obj* m_obj = NULL; + #define RETURN_FROM_GET RETURN_FALSE @@ -133,37 +132,48 @@ enum memcached_compression_type { }; typedef struct { - struct memc_obj { - memcached_st *memc; - zend_bool compression; - enum memcached_serializer serializer; - enum memcached_compression_type compression_type; + + zend_bool is_persistent; + zend_bool compression; + enum memcached_serializer serializer; + enum memcached_compression_type compression_type; + + zend_long store_retry_count; + zend_long set_udf_flags; + #if HAVE_MEMCACHED_SASL - zend_bool has_sasl_data; + zend_bool has_sasl_data; #endif - long store_retry_count; - zend_long set_udf_flags; - } *obj; - zend_bool is_persistent; +} php_memc_user_data_t; + + +typedef struct { + memcached_st *memc; zend_bool is_pristine; int rescode; int memc_errno; zend_object zo; -} php_memc_t; +} php_memc_object_t; -static inline php_memc_t *php_memc_fetch_object(zend_object *obj) { - return (php_memc_t *)((char *)obj - XtOffsetOf(php_memc_t, zo)); +static inline php_memc_object_t *php_memc_fetch_object(zend_object *obj) { + return (php_memc_object_t *)((char *)obj - XtOffsetOf(php_memc_object_t, zo)); } #define Z_MEMC_OBJ_P(zv) php_memc_fetch_object(Z_OBJ_P(zv)); -#define MEMC_METHOD_FETCH_OBJECT \ - i_obj = Z_MEMC_OBJ_P(object); \ - m_obj = i_obj->obj; \ - if (!m_obj) { \ - php_error_docref(NULL, E_WARNING, "Memcached constructor was not called"); \ - return; \ - } +#define MEMC_METHOD_INIT_VARS \ + zval* object = getThis(); \ + php_memc_object_t* intern = NULL; \ + php_memc_user_data_t* memc_user_data = NULL; + +#define MEMC_METHOD_FETCH_OBJECT \ + intern = Z_MEMC_OBJ_P(object); \ + if (!intern->memc) { \ + php_error_docref(NULL, E_WARNING, "Memcached constructor was not called"); \ + return; \ + } \ + memc_user_data = (php_memc_user_data_t *) memcached_get_user_data(intern->memc); + #ifdef HAVE_MEMCACHED_PROTOCOL @@ -194,15 +204,6 @@ static zend_object_handlers memcached_server_object_handlers; static zend_class_entry *memcached_server_ce = NULL; #endif -struct callbackContext -{ - zval *array; - zval *entry; - memcached_stat_st *stats; /* for use with functions that need stats */ - void *return_value; - unsigned int i; /* for use with structures mapped against servers */ -}; - #if HAVE_SPL static zend_class_entry *spl_ce_RuntimeException = NULL; #endif @@ -254,22 +255,51 @@ static PHP_INI_MH(OnUpdateSerializer) return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); } +static +PHP_INI_MH(OnUpdateDeprecatedLockValue) +{ + if (new_value->len > 0 && strcmp(new_value->val, "not set")) { + php_error_docref(NULL, E_DEPRECATED, "memcached.sess_lock_wait and memcached.sess_lock_max_wait are deprecated. Please update your configuration to use memcached.sess_lock_wait_min, memcached.sess_lock_wait_max and memcached.sess_lock_retries"); + } + return FAILURE; +} + +static +PHP_INI_MH(OnUpdateSessionPrefixString) +{ + if (new_value && new_value->len > 0) { + char *ptr = new_value->val; + + while (*ptr != '\0') { + if (isspace (*ptr++)) { + php_error_docref(NULL, E_WARNING, "memcached.sess_prefix cannot contain whitespace characters"); + return FAILURE; + } + } + if (new_value->len > MEMCACHED_MAX_KEY) { + php_error_docref(NULL, E_WARNING, "memcached.sess_prefix too long (max: %d)", MEMCACHED_MAX_KEY - 1); + return FAILURE; + } + } + return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); +} + #define MEMC_INI_ENTRY(key, default_value, update_fn, gkey) \ STD_PHP_INI_ENTRY("memcached."key, default_value, PHP_INI_ALL, update_fn, memc_ini.gkey, zend_php_memcached_globals, php_memcached_globals) #define MEMC_SESSION_INI_ENTRY(key, default_value, update_fn, gkey) \ - STD_PHP_INI_ENTRY("memcached.session."key, default_value, PHP_INI_ALL, update_fn, session_ini.gkey, zend_php_memcached_globals, php_memcached_globals) + STD_PHP_INI_ENTRY("memcached.sess_"key, default_value, PHP_INI_ALL, update_fn, session_ini.gkey, zend_php_memcached_globals, php_memcached_globals) /* {{{ INI entries */ PHP_INI_BEGIN() #ifdef HAVE_MEMCACHED_SESSION - MEMC_SESSION_INI_ENTRY("lock_enabled", "1", OnUpdateBool, lock_enabled) + MEMC_SESSION_INI_ENTRY("locking", "1", OnUpdateBool, lock_enabled) MEMC_SESSION_INI_ENTRY("lock_wait_min", "1000", OnUpdateLongGEZero, lock_wait_min) MEMC_SESSION_INI_ENTRY("lock_wait_max", "2000", OnUpdateLongGEZero, lock_wait_max) MEMC_SESSION_INI_ENTRY("lock_retries", "5", OnUpdateLongGEZero, lock_retries) - MEMC_SESSION_INI_ENTRY("lock_expiration", "0", OnUpdateLongGEZero, lock_expiration) + MEMC_SESSION_INI_ENTRY("lock_expire", "0", OnUpdateLongGEZero, lock_expiration) MEMC_SESSION_INI_ENTRY("compression", "1", OnUpdateBool, compression_enabled) MEMC_SESSION_INI_ENTRY("binary_protocol", "1", OnUpdateBool, binary_protocol_enabled) MEMC_SESSION_INI_ENTRY("consistent_hash", "1", OnUpdateBool, consistent_hash_enabled) @@ -280,8 +310,13 @@ PHP_INI_BEGIN() MEMC_SESSION_INI_ENTRY("connect_timeout", "0", OnUpdateLongGEZero, connect_timeout) MEMC_SESSION_INI_ENTRY("sasl_username", "", OnUpdateString, sasl_username) MEMC_SESSION_INI_ENTRY("sasl_password", "", OnUpdateString, sasl_password) - MEMC_SESSION_INI_ENTRY("prefix", "memc.sess.", OnUpdateString, prefix) + MEMC_SESSION_INI_ENTRY("prefix", "memc.sess.", OnUpdateSessionPrefixString, prefix) MEMC_SESSION_INI_ENTRY("persistent", "0", OnUpdateBool, persistent_enabled) + + /* Deprecated */ + STD_PHP_INI_ENTRY("memcached.sess_lock_wait", "not set", PHP_INI_ALL, OnUpdateDeprecatedLockValue, no_effect, zend_php_memcached_globals, php_memcached_globals) + STD_PHP_INI_ENTRY("memcached.sess_lock_max_wait", "not set", PHP_INI_ALL, OnUpdateDeprecatedLockValue, no_effect, zend_php_memcached_globals, php_memcached_globals) + #endif MEMC_INI_ENTRY("compression_type", "fastlz", OnUpdateCompressionType, compression_type) @@ -299,7 +334,7 @@ PHP_INI_END() /**************************************** Forward declarations ****************************************/ -static int php_memc_handle_error(php_memc_t *i_obj, memcached_return status); +static int php_memc_handle_error(php_memc_object_t *intern, memcached_return status); static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key); static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key); @@ -308,14 +343,27 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke static void php_memc_delete_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key); static void php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key); static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key); -static memcached_return php_memc_do_cache_callback(zval *memc_obj, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string *key, zval *value); -static int php_memc_do_result_callback(zval *memc_obj, zend_fcall_info *fci, zend_fcall_info_cache *fcc, memcached_result_st *result); -static memcached_return php_memc_do_serverlist_callback(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context); -static memcached_return php_memc_do_stats_callback(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context); -static memcached_return php_memc_do_version_callback(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context); -static void php_memc_destroy(struct memc_obj *m_obj, zend_bool persistent); + +/* Invoke PHP functions */ +static + memcached_return s_invoke_cache_callback(zval *zobject, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string *key, zval *value); + +static + int s_invoke_result_callback(zval *zmemc_obj, zend_fcall_info *fci, zend_fcall_info_cache *fcc, memcached_result_st *result); + +/* Callback functions for different server list iterations */ +static + memcached_return s_server_cursor_list_servers_cb(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context); + +static + memcached_return s_server_cursor_version_cb(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context); + +/* Callback for dumping all keys to zval */ +static + void php_memc_destroy(memcached_st *memc, php_memc_user_data_t *memc_user_data); + static zend_bool s_memcached_result_to_zval(memcached_result_st *result, zval *return_value); @@ -364,7 +412,8 @@ char *php_memc_printable_func (zend_fcall_info *fci, zend_fcall_info_cache *fci_ return buffer; } -static zend_bool php_memcached_on_new_callback(zval *object, zend_fcall_info *fci, zend_fcall_info_cache *fci_cache, zend_string *persistent_id) +static +zend_bool s_invoke_new_instance_cb(zval *object, zend_fcall_info *fci, zend_fcall_info_cache *fci_cache, zend_string *persistent_id) { zend_bool ret = 1; zval retval, id; @@ -388,17 +437,23 @@ static zend_bool php_memcached_on_new_callback(zval *object, zend_fcall_info *fc ret = 0; } - if (Z_TYPE(retval) != IS_UNDEF) + if (Z_TYPE(retval) != IS_UNDEF) { zval_ptr_dtor(&retval); + } - zend_fcall_info_args_clear(fci, 1); + if (EG(exception)) { + ret = 0; + } + zend_fcall_info_args_clear(fci, 1); return ret; } -static int le_memc; +static + int le_memc; -static int php_memc_list_entry(void) +static +int php_memc_list_entry(void) { return le_memc; } @@ -407,22 +462,23 @@ static int php_memc_list_entry(void) Creates a Memcached object, optionally using persistent memcache connection */ static PHP_METHOD(Memcached, __construct) { - zval *object = getThis(); - php_memc_t *i_obj; - struct memc_obj *m_obj = NULL; + php_memc_object_t *intern; + php_memc_user_data_t *memc_user_data; + zend_string *persistent_id = NULL; zend_string *conn_str = NULL; zend_string *plist_key = NULL; zend_fcall_info fci = {0}; zend_fcall_info_cache fci_cache; + zend_bool is_persistent = 0; + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!f!S", &persistent_id, &fci, &fci_cache, &conn_str) == FAILURE) { return; } - i_obj = Z_MEMC_OBJ_P(object); - i_obj->is_pristine = 0; - i_obj->is_persistent = 0; + intern = Z_MEMC_OBJ_P(getThis()); + intern->is_pristine = 1; if (persistent_id && persistent_id->len) { zend_resource *le; @@ -432,18 +488,74 @@ static PHP_METHOD(Memcached, __construct) if ((le = zend_hash_find_ptr(&EG(persistent_list), plist_key)) != NULL) { if (le->type == php_memc_list_entry()) { - m_obj = (struct memc_obj *) le->ptr; - - i_obj->obj = m_obj; - i_obj->is_persistent = 1; + intern->memc = le->ptr; + intern->is_pristine = 0; zend_string_release (plist_key); return; } } - i_obj->is_persistent = 1; + is_persistent = 1; + } + + if (conn_str && conn_str->len > 0) { + intern->memc = memcached (conn_str->val, conn_str->len); + } + else { + intern->memc = memcached (NULL, 0); + } + + if (!intern->memc) { + // TODO: handle allocation fail + } + + memc_user_data = pecalloc (1, sizeof(*memc_user_data), is_persistent); + memc_user_data->serializer = MEMC_G(serializer); + memc_user_data->compression_type = MEMC_G(compression_type_real); + memc_user_data->compression = 1; + memc_user_data->store_retry_count = MEMC_G(store_retry_count); + memc_user_data->set_udf_flags = -1; + memc_user_data->is_persistent = is_persistent; + + memcached_set_user_data(intern->memc, memc_user_data); + + if (fci.size) { + if (!s_invoke_new_instance_cb(getThis(), &fci, &fci_cache, persistent_id) || EG(exception)) { + /* error calling or exception thrown from callback */ + if (plist_key) { + zend_string_release(plist_key); + } + /* + Setting intern->memc null prevents object destruction from freeing the memcached_st + We free it manually here because it might be persistent and has not been + registered to persistent_list yet + */ + php_memc_destroy(intern->memc, memc_user_data); + intern->memc = NULL; + return; + } } - m_obj = pecalloc(1, sizeof(*m_obj), i_obj->is_persistent); + if (plist_key) { + zend_resource le; + + le.type = php_memc_list_entry(); + le.ptr = intern->memc; + + GC_REFCOUNT(&le) = 1; + + /* plist_key is not a persistent allocated key, thus we use str_update here */ + if (zend_hash_str_update_mem(&EG(persistent_list), plist_key->val, plist_key->len, &le, sizeof(le)) == NULL) { + zend_string_release(plist_key); + php_error_docref(NULL, E_ERROR, "could not register persistent entry"); + /* not reached */ + } + zend_string_release(plist_key); + } + + + +#if 0 + m_obj = pecalloc(1, sizeof(*m_obj), intern->is_persistent); if (m_obj == NULL) { if (plist_key) { zend_string_release(plist_key); @@ -453,8 +565,8 @@ static PHP_METHOD(Memcached, __construct) } if (conn_str) { - m_obj->memc = php_memc_create_str(conn_str->val, conn_str->len); - if (!m_obj->memc) { + intern->memc = php_memc_create_str(conn_str->val, conn_str->len); + if (!intern->memc) { char error_buffer[1024]; if (plist_key) { zend_string_release(plist_key); @@ -471,8 +583,8 @@ static PHP_METHOD(Memcached, __construct) /* not reached */ } } else { - m_obj->memc = memcached_create(NULL); - if (m_obj->memc == NULL) { + intern->memc = memcached_create(NULL); + if (intern->memc == NULL) { if (plist_key) { zend_string_release(plist_key); } @@ -481,14 +593,10 @@ static PHP_METHOD(Memcached, __construct) } } - m_obj->serializer = MEMC_G(serializer); - m_obj->compression_type = MEMC_G(compression_type_real); - m_obj->compression = 1; - m_obj->store_retry_count = MEMC_G(store_retry_count); - m_obj->set_udf_flags = -1; - i_obj->obj = m_obj; - i_obj->is_pristine = 1; + + intern->obj = m_obj; + intern->is_pristine = 1; if (fci.size) { /* will be 0 when not available */ if (!php_memcached_on_new_callback(object, &fci, &fci_cache, persistent_id) || EG(exception)) { @@ -497,16 +605,16 @@ static PHP_METHOD(Memcached, __construct) zend_string_release(plist_key); } - i_obj->obj = NULL; - if (i_obj->is_persistent) { - php_memc_destroy(m_obj, i_obj->is_persistent); + intern->obj = NULL; + if (intern->is_persistent) { + php_memc_destroy(m_obj, intern->is_persistent); } return; } } - if (i_obj->is_persistent) { + if (intern->is_persistent) { zend_resource le; le.type = php_memc_list_entry(); @@ -525,6 +633,7 @@ static PHP_METHOD(Memcached, __construct) if (plist_key) { zend_string_release(plist_key); } +#endif } /* }}} */ @@ -775,14 +884,14 @@ void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) } MEMC_METHOD_FETCH_OBJECT; - i_obj->rescode = MEMCACHED_SUCCESS; + intern->rescode = MEMCACHED_SUCCESS; zend_hash_init (&keys, 1, 0, NULL, 0); ZVAL_STR(&tmp, key); zend_hash_add(&keys, key, &tmp); ZVAL_UNDEF(&values); - status = s_memcached_get_multi(m_obj->memc, &keys, server_key, get_flags, &values); + status = s_memcached_get_multi(intern->memc, &keys, server_key, get_flags, &values); zend_hash_destroy (&keys); if (EG(exception)) { @@ -808,10 +917,10 @@ void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) if (status == MEMCACHED_NOTFOUND && fci.size > 0) { // try to invoke cache cb - status = php_memc_do_cache_callback(getThis(), &fci, &fcc, key, return_value); + status = s_invoke_cache_callback(object, &fci, &fcc, key, return_value); } - if (php_memc_handle_error(i_obj, status) < 0) { + if (php_memc_handle_error(intern, status) < 0) { RETURN_FROM_GET; } } @@ -854,8 +963,8 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke MEMC_METHOD_FETCH_OBJECT; - rc = s_memcached_get_multi(m_obj->memc, Z_ARRVAL_P(keys), server_key, flags, return_value); - php_memc_handle_error(i_obj, rc); + rc = s_memcached_get_multi(intern->memc, Z_ARRVAL_P(keys), server_key, flags, return_value); + php_memc_handle_error(intern, rc); if (EG(exception)) { zval_dtor(return_value); @@ -926,7 +1035,7 @@ static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ } MEMC_METHOD_FETCH_OBJECT; - i_obj->rescode = MEMCACHED_SUCCESS; + intern->rescode = MEMCACHED_SUCCESS; /* * Create the array of keys for libmemcached. If none of the keys were valid @@ -949,7 +1058,7 @@ static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ } ZEND_HASH_FOREACH_END(); if (i == 0) { - i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; + intern->rescode = MEMCACHED_BAD_KEY_PROVIDED; efree(mkeys); efree(mkeys_len); zval_dtor(return_value); @@ -960,9 +1069,9 @@ static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ * Enable CAS support, but only if it is currently disabled. */ if (with_cas) { - orig_cas_flag = memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS); + orig_cas_flag = memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS); if (orig_cas_flag == 0) { - memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1); + memcached_behavior_set(intern->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1); } } @@ -970,20 +1079,20 @@ static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ * Issue the request, but collect results only if the result callback is provided. */ if (by_key) { - status = memcached_mget_by_key(m_obj->memc, server_key->val, server_key->len, mkeys, mkeys_len, i); + status = memcached_mget_by_key(intern->memc, server_key->val, server_key->len, mkeys, mkeys_len, i); } else { - status = memcached_mget(m_obj->memc, mkeys, mkeys_len, i); + status = memcached_mget(intern->memc, mkeys, mkeys_len, i); } /* * Restore the CAS support flag, but only if we had to turn it on. */ if (with_cas && orig_cas_flag == 0) { - memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, orig_cas_flag); + memcached_behavior_set(intern->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, orig_cas_flag); } efree(mkeys); efree(mkeys_len); - if (php_memc_handle_error(i_obj, status) < 0) { + if (php_memc_handle_error(intern, status) < 0) { zval_dtor(return_value); RETURN_FALSE; } @@ -995,9 +1104,9 @@ static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ */ memcached_result_st result; - memcached_result_create(m_obj->memc, &result); - while ((memcached_fetch_result(m_obj->memc, &result, &status)) != NULL) { - if (php_memc_do_result_callback(getThis(), &fci, &fcc, &result) < 0) { + memcached_result_create(intern->memc, &result); + while ((memcached_fetch_result(intern->memc, &result, &status)) != NULL) { + if (s_invoke_result_callback(getThis(), &fci, &fcc, &result) < 0) { status = MEMCACHED_FAILURE; break; } @@ -1008,7 +1117,7 @@ static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ if (status == MEMCACHED_END) { status = MEMCACHED_SUCCESS; } - if (php_memc_handle_error(i_obj, status) < 0) { + if (php_memc_handle_error(intern, status) < 0) { RETURN_FALSE; } } @@ -1037,11 +1146,11 @@ PHP_METHOD(Memcached, fetch) } MEMC_METHOD_FETCH_OBJECT; - i_obj->rescode = MEMCACHED_SUCCESS; + intern->rescode = MEMCACHED_SUCCESS; - memcached_result_create(m_obj->memc, &result); - if ((memcached_fetch_result(m_obj->memc, &result, &status)) == NULL) { - php_memc_handle_error(i_obj, status); + memcached_result_create(intern->memc, &result); + if ((memcached_fetch_result(intern->memc, &result, &status)) == NULL) { + php_memc_handle_error(intern, status); memcached_result_free(&result); RETURN_FALSE; } @@ -1055,7 +1164,7 @@ PHP_METHOD(Memcached, fetch) if (!s_memcached_result_to_zval(&result, &value)) { memcached_result_free(&result); - i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE; + intern->rescode = MEMC_RES_PAYLOAD_FAILURE; RETURN_FALSE; } @@ -1094,12 +1203,12 @@ PHP_METHOD(Memcached, fetchAll) } MEMC_METHOD_FETCH_OBJECT; - i_obj->rescode = MEMCACHED_SUCCESS; + intern->rescode = MEMCACHED_SUCCESS; array_init(return_value); - memcached_result_create(m_obj->memc, &result); + memcached_result_create(intern->memc, &result); - while ((memcached_fetch_result(m_obj->memc, &result, &status)) != NULL) { + while ((memcached_fetch_result(intern->memc, &result, &status)) != NULL) { payload = memcached_result_value(&result); payload_len = memcached_result_length(&result); flags = memcached_result_flags(&result); @@ -1110,7 +1219,7 @@ PHP_METHOD(Memcached, fetchAll) if (!s_memcached_result_to_zval(&result, &value)) { memcached_result_free(&result); zval_dtor(return_value); - i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE; + intern->rescode = MEMC_RES_PAYLOAD_FAILURE; RETURN_FALSE; } @@ -1129,7 +1238,7 @@ PHP_METHOD(Memcached, fetchAll) memcached_result_free(&result); - if (status != MEMCACHED_END && php_memc_handle_error(i_obj, status) < 0) { + if (status != MEMCACHED_END && php_memc_handle_error(intern, status) < 0) { zval_dtor(return_value); RETURN_FALSE; } @@ -1188,8 +1297,8 @@ PHP_METHOD(Memcached, setMultiByKey) /* }}} */ #define PHP_MEMC_FAILOVER_RETRY \ - if (!by_key && retry < m_obj->store_retry_count) { \ - switch (i_obj->rescode) { \ + if (!by_key && retry < memc_user_data->store_retry_count) { \ + switch (intern->rescode) { \ case MEMCACHED_HOST_LOOKUP_FAILURE: \ case MEMCACHED_CONNECTION_FAILURE: \ case MEMCACHED_CONNECTION_BIND_FAILURE: \ @@ -1203,9 +1312,9 @@ PHP_METHOD(Memcached, setMultiByKey) case MEMCACHED_FAIL_UNIX_SOCKET: \ case MEMCACHED_SERVER_MARKED_DEAD: \ case MEMCACHED_SERVER_TEMPORARILY_DISABLED: \ - if (memcached_server_count(m_obj->memc) > 0) { \ + if (memcached_server_count(intern->memc) > 0) { \ retry++; \ - i_obj->rescode = 0; \ + intern->rescode = 0; \ goto retry; \ } \ break; \ @@ -1241,7 +1350,7 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke } MEMC_METHOD_FETCH_OBJECT; - i_obj->rescode = MEMCACHED_SUCCESS; + intern->rescode = MEMCACHED_SUCCESS; ZEND_HASH_FOREACH_KEY_VAL (Z_ARRVAL_P(entries), num_key, skey, value) { if (skey) { @@ -1258,17 +1367,17 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke } flags = 0; - if (m_obj->compression) { + if (memc_user_data->compression) { MEMC_VAL_SET_FLAG(flags, MEMC_VAL_COMPRESSED); } - if (m_obj->set_udf_flags >= 0) { - MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) m_obj->set_udf_flags)); + if (memc_user_data->set_udf_flags >= 0) { + MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) memc_user_data->set_udf_flags)); } - payload = s_zval_to_payload(value, &flags, m_obj->serializer, m_obj->compression_type); + payload = s_zval_to_payload(value, &flags, memc_user_data->serializer, memc_user_data->compression_type); if (payload == NULL) { - i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE; + intern->rescode = MEMC_RES_PAYLOAD_FAILURE; if (!skey) { zend_string_release(str_key); } @@ -1277,12 +1386,12 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke retry: if (!by_key) { - status = memcached_set(m_obj->memc, str_key->val, str_key->len, payload->val, payload->len, expiration, flags); + status = memcached_set(intern->memc, str_key->val, str_key->len, payload->val, payload->len, expiration, flags); } else { - status = memcached_set_by_key(m_obj->memc, server_key->val, server_key->len, str_key->val, str_key->len, payload->val, payload->len, expiration, flags); + status = memcached_set_by_key(intern->memc, server_key->val, server_key->len, str_key->val, str_key->len, payload->val, payload->len, expiration, flags); } - if (php_memc_handle_error(i_obj, status) < 0) { + if (php_memc_handle_error(intern, status) < 0) { PHP_MEMC_FAILOVER_RETRY if (!skey) { zend_string_release(str_key); @@ -1414,14 +1523,9 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool } MEMC_METHOD_FETCH_OBJECT; - i_obj->rescode = MEMCACHED_SUCCESS; + intern->rescode = MEMCACHED_SUCCESS; - if (key->len == 0 || (!memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) && strchr(key->val, ' '))) { - i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; - RETURN_FALSE; - } - - if (m_obj->compression) { + if (memc_user_data->compression) { /* * When compression is enabled, we cannot do appends/prepends because that would * corrupt the compressed values. It is up to the user to fetch the value, @@ -1438,21 +1542,21 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool * php_memcached uses 16 bits internally to store type, compression and serialization info. * We use 16 upper bits to store user defined flags. */ - if (m_obj->set_udf_flags >= 0) { - MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) m_obj->set_udf_flags)); + if (memc_user_data->set_udf_flags >= 0) { + MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) memc_user_data->set_udf_flags)); } if (op == MEMC_OP_TOUCH) { #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x01000016 - if (memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) { + if (memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) { php_error_docref(NULL, E_WARNING, "using touch command with binary protocol is not recommended with libmemcached versions below 1.0.16"); } #endif } else { - payload = s_zval_to_payload(value, &flags, m_obj->serializer, m_obj->compression_type); + payload = s_zval_to_payload(value, &flags, memc_user_data->serializer, memc_user_data->compression_type); if (payload == NULL) { - i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE; + intern->rescode = MEMC_RES_PAYLOAD_FAILURE; RETURN_FALSE; } } @@ -1460,54 +1564,54 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool switch (op) { case MEMC_OP_SET: if (!server_key) { - status = memcached_set(m_obj->memc, key->val, key->len, payload->val, payload->len, expiration, flags); + status = memcached_set(intern->memc, key->val, key->len, payload->val, payload->len, expiration, flags); } else { - status = memcached_set_by_key(m_obj->memc, server_key->val, server_key->len, key->val, + status = memcached_set_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, payload->val, payload->len, expiration, flags); } break; #ifdef HAVE_MEMCACHED_TOUCH case MEMC_OP_TOUCH: if (!server_key) { - status = memcached_touch(m_obj->memc, key->val, key->len, expiration); + status = memcached_touch(intern->memc, key->val, key->len, expiration); } else { - status = memcached_touch_by_key(m_obj->memc, server_key->val, server_key->len, key->val, + status = memcached_touch_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, expiration); } break; #endif case MEMC_OP_ADD: if (!server_key) { - status = memcached_add(m_obj->memc, key->val, key->len, payload->val, payload->len, expiration, flags); + status = memcached_add(intern->memc, key->val, key->len, payload->val, payload->len, expiration, flags); } else { - status = memcached_add_by_key(m_obj->memc, server_key->val, server_key->len, key->val, + status = memcached_add_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, payload->val, payload->len, expiration, flags); } break; case MEMC_OP_REPLACE: if (!server_key) { - status = memcached_replace(m_obj->memc, key->val, key->len, payload->val, payload->len, expiration, flags); + status = memcached_replace(intern->memc, key->val, key->len, payload->val, payload->len, expiration, flags); } else { - status = memcached_replace_by_key(m_obj->memc, server_key->val, server_key->len, key->val, + status = memcached_replace_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, payload->val, payload->len, expiration, flags); } break; case MEMC_OP_APPEND: if (!server_key) { - status = memcached_append(m_obj->memc, key->val, key->len, payload->val, payload->len, expiration, flags); + status = memcached_append(intern->memc, key->val, key->len, payload->val, payload->len, expiration, flags); } else { - status = memcached_append_by_key(m_obj->memc, server_key->val, server_key->len, key->val, + status = memcached_append_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, payload->val, payload->len, expiration, flags); } break; case MEMC_OP_PREPEND: if (!server_key) { - status = memcached_prepend(m_obj->memc, key->val, key->len, payload->val, payload->len, expiration, flags); + status = memcached_prepend(intern->memc, key->val, key->len, payload->val, payload->len, expiration, flags); } else { - status = memcached_prepend_by_key(m_obj->memc, server_key->val, server_key->len, key->val, + status = memcached_prepend_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, payload->val, payload->len, expiration, flags); } break; @@ -1519,7 +1623,7 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool break; } - if (php_memc_handle_error(i_obj, status) < 0) { + if (php_memc_handle_error(intern, status) < 0) { PHP_MEMC_FAILOVER_RETRY RETVAL_FALSE; } else { @@ -1559,16 +1663,11 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) } MEMC_METHOD_FETCH_OBJECT; - i_obj->rescode = MEMCACHED_SUCCESS; - - if (key->len == 0 || (!memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) && strchr(key->val, ' '))) { - i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; - RETURN_FALSE; - } + intern->rescode = MEMCACHED_SUCCESS; cas = s_zval_to_uint64(zv_cas); - if (m_obj->compression) { + if (memc_user_data->compression) { MEMC_VAL_SET_FLAG(flags, MEMC_VAL_COMPRESSED); } @@ -1576,24 +1675,24 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) * php_memcached uses 16 bits internally to store type, compression and serialization info. * We use 16 upper bits to store user defined flags. */ - if (m_obj->set_udf_flags >= 0) { - MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) m_obj->set_udf_flags)); + if (memc_user_data->set_udf_flags >= 0) { + MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) memc_user_data->set_udf_flags)); } - payload = s_zval_to_payload(value, &flags, m_obj->serializer, m_obj->compression_type); + payload = s_zval_to_payload(value, &flags, memc_user_data->serializer, memc_user_data->compression_type); if (payload == NULL) { - i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE; + intern->rescode = MEMC_RES_PAYLOAD_FAILURE; RETURN_FALSE; } if (by_key) { - status = memcached_cas_by_key(m_obj->memc, server_key->val, server_key->len, key->val, key->len, payload->val, payload->len, expiration, flags, cas); + status = memcached_cas_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, payload->val, payload->len, expiration, flags, cas); } else { - status = memcached_cas(m_obj->memc, key->val, key->len, payload->val, payload->len, expiration, flags, cas); + status = memcached_cas(intern->memc, key->val, key->len, payload->val, payload->len, expiration, flags, cas); } zend_string_release(payload); - if (php_memc_handle_error(i_obj, status) < 0) { + if (php_memc_handle_error(intern, status) < 0) { RETURN_FALSE; } @@ -1669,21 +1768,16 @@ static void php_memc_delete_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) } MEMC_METHOD_FETCH_OBJECT; - i_obj->rescode = MEMCACHED_SUCCESS; - - if (key->len == 0 || (!memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) && strchr(key->val, ' '))) { - i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; - RETURN_FALSE; - } + intern->rescode = MEMCACHED_SUCCESS; if (by_key) { - status = memcached_delete_by_key(m_obj->memc, server_key->val, server_key->len, key->val, + status = memcached_delete_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, expiration); } else { - status = memcached_delete(m_obj->memc, key->val, key->len, expiration); + status = memcached_delete(intern->memc, key->val, key->len, expiration); } - if (php_memc_handle_error(i_obj, status) < 0) { + if (php_memc_handle_error(intern, status) < 0) { RETURN_FALSE; } @@ -1713,7 +1807,7 @@ static void php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by } MEMC_METHOD_FETCH_OBJECT; - i_obj->rescode = MEMCACHED_SUCCESS; + intern->rescode = MEMCACHED_SUCCESS; array_init(return_value); ZEND_HASH_FOREACH_VAL (Z_ARRVAL_P(entries), entry) { @@ -1726,13 +1820,13 @@ static void php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by } if (by_key) { - status = memcached_delete_by_key(m_obj->memc, server_key->val, server_key->len, Z_STRVAL_P(entry), Z_STRLEN_P(entry), expiration); + status = memcached_delete_by_key(intern->memc, server_key->val, server_key->len, Z_STRVAL_P(entry), Z_STRLEN_P(entry), expiration); } else { - status = memcached_delete_by_key(m_obj->memc, Z_STRVAL_P(entry), Z_STRLEN_P(entry), Z_STRVAL_P(entry), Z_STRLEN_P(entry), expiration); + status = memcached_delete_by_key(intern->memc, Z_STRVAL_P(entry), Z_STRLEN_P(entry), Z_STRVAL_P(entry), Z_STRLEN_P(entry), expiration); } - if (php_memc_handle_error(i_obj, status) < 0) { + if (php_memc_handle_error(intern, status) < 0) { add_assoc_long(return_value, Z_STRVAL_P(entry), status); } else { add_assoc_bool(return_value, Z_STRVAL_P(entry), 1); @@ -1767,12 +1861,7 @@ static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key, } MEMC_METHOD_FETCH_OBJECT; - i_obj->rescode = MEMCACHED_SUCCESS; - - if (key->len == 0 || (!memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) && strchr(key->val, ' '))) { - i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; - RETURN_FALSE; - } + intern->rescode = MEMCACHED_SUCCESS; if (offset < 0) { php_error_docref(NULL, E_WARNING, "offset has to be > 0"); @@ -1783,38 +1872,38 @@ static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key, if ((!by_key && n_args < 3) || (by_key && n_args < 4)) { if (by_key) { if (incr) { - status = memcached_increment_by_key(m_obj->memc, server_key->val, server_key->len, key->val, key->len, (unsigned int)offset, &value); + status = memcached_increment_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, (unsigned int)offset, &value); } else { - status = memcached_decrement_by_key(m_obj->memc, server_key->val, server_key->len, key->val, key->len, (unsigned int)offset, &value); + status = memcached_decrement_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, (unsigned int)offset, &value); } } else { if (incr) { - status = memcached_increment(m_obj->memc, key->val, key->len, (unsigned int)offset, &value); + status = memcached_increment(intern->memc, key->val, key->len, (unsigned int)offset, &value); } else { - status = memcached_decrement(m_obj->memc, key->val, key->len, (unsigned int)offset, &value); + status = memcached_decrement(intern->memc, key->val, key->len, (unsigned int)offset, &value); } } } else { - if (!memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) { + if (!memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) { php_error_docref(NULL, E_WARNING, "Initial value is only supported with binary protocol"); RETURN_FALSE; } if (by_key) { if (incr) { - status = memcached_increment_with_initial_by_key(m_obj->memc, server_key->val, server_key->len, key->val, key->len, (unsigned int)offset, initial, expiry, &value); + status = memcached_increment_with_initial_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, (unsigned int)offset, initial, expiry, &value); } else { - status = memcached_decrement_with_initial_by_key(m_obj->memc, server_key->val, server_key->len, key->val, key->len, (unsigned int)offset, initial, expiry, &value); + status = memcached_decrement_with_initial_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, (unsigned int)offset, initial, expiry, &value); } } else { if (incr) { - status = memcached_increment_with_initial(m_obj->memc, key->val, key->len, (unsigned int)offset, initial, expiry, &value); + status = memcached_increment_with_initial(intern->memc, key->val, key->len, (unsigned int)offset, initial, expiry, &value); } else { - status = memcached_decrement_with_initial(m_obj->memc, key->val, key->len, (unsigned int)offset, initial, expiry, &value); + status = memcached_decrement_with_initial(intern->memc, key->val, key->len, (unsigned int)offset, initial, expiry, &value); } } } - if (php_memc_handle_error(i_obj, status) < 0) { + if (php_memc_handle_error(intern, status) < 0) { PHP_MEMC_FAILOVER_RETRY RETURN_FALSE; } @@ -1869,21 +1958,21 @@ PHP_METHOD(Memcached, addServer) } MEMC_METHOD_FETCH_OBJECT; - i_obj->rescode = MEMCACHED_SUCCESS; + intern->rescode = MEMCACHED_SUCCESS; #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x01000002 if (host->val[0] == '/') { /* unix domain socket */ - status = memcached_server_add_unix_socket_with_weight(m_obj->memc, host->val, weight); - } else if (memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_USE_UDP)) { - status = memcached_server_add_udp_with_weight(m_obj->memc, host->val, port, weight); + status = memcached_server_add_unix_socket_with_weight(intern->memc, host->val, weight); + } else if (memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_USE_UDP)) { + status = memcached_server_add_udp_with_weight(intern->memc, host->val, port, weight); } else { - status = memcached_server_add_with_weight(m_obj->memc, host->val, port, weight); + status = memcached_server_add_with_weight(intern->memc, host->val, port, weight); } #else - status = memcached_server_add_with_weight(m_obj->memc, host->val, port, weight); + status = memcached_server_add_with_weight(intern->memc, host->val, port, weight); #endif - if (php_memc_handle_error(i_obj, status) < 0) { + if (php_memc_handle_error(intern, status) < 0) { RETURN_FALSE; } @@ -1910,7 +1999,7 @@ PHP_METHOD(Memcached, addServers) } MEMC_METHOD_FETCH_OBJECT; - i_obj->rescode = MEMCACHED_SUCCESS; + intern->rescode = MEMCACHED_SUCCESS; ZEND_HASH_FOREACH_VAL (Z_ARRVAL_P(servers), entry) { if (Z_TYPE_P(entry) != IS_ARRAY) { @@ -1957,7 +2046,7 @@ PHP_METHOD(Memcached, addServers) list = memcached_server_list_append_with_weight(list, Z_STRVAL_P(z_host), Z_LVAL_P(z_port), weight, &status); - if (php_memc_handle_error(i_obj, status) == 0) { + if (php_memc_handle_error(intern, status) == 0) { i++; continue; } @@ -1967,9 +2056,9 @@ PHP_METHOD(Memcached, addServers) php_error_docref(NULL, E_WARNING, "could not add entry #%d to the server list", i+1); } ZEND_HASH_FOREACH_END(); - status = memcached_server_push(m_obj->memc, list); + status = memcached_server_push(intern->memc, list); memcached_server_list_free(list); - if (php_memc_handle_error(i_obj, status) < 0) { + if (php_memc_handle_error(intern, status) < 0) { RETURN_FALSE; } @@ -1981,7 +2070,6 @@ PHP_METHOD(Memcached, addServers) Returns the list of the memcache servers in use */ PHP_METHOD(Memcached, getServerList) { - struct callbackContext context = {0}; memcached_server_function callbacks[1]; MEMC_METHOD_INIT_VARS; @@ -1991,10 +2079,9 @@ PHP_METHOD(Memcached, getServerList) MEMC_METHOD_FETCH_OBJECT; - callbacks[0] = php_memc_do_serverlist_callback; + callbacks[0] = s_server_cursor_list_servers_cb; array_init(return_value); - context.return_value = return_value; - memcached_server_cursor(m_obj->memc, callbacks, &context, 1); + memcached_server_cursor(intern->memc, callbacks, return_value, 1); } /* }}} */ @@ -2012,16 +2099,11 @@ PHP_METHOD(Memcached, getServerByKey) } MEMC_METHOD_FETCH_OBJECT; - i_obj->rescode = MEMCACHED_SUCCESS; - - if (server_key->len == 0 || (!memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) && strchr(server_key->val, ' '))) { - i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; - RETURN_FALSE; - } + intern->rescode = MEMCACHED_SUCCESS; - server_instance = memcached_server_by_key(m_obj->memc, server_key->val, server_key->len, &error); + server_instance = memcached_server_by_key(intern->memc, server_key->val, server_key->len, &error); if (server_instance == NULL) { - php_memc_handle_error(i_obj, error); + php_memc_handle_error(intern, error); RETURN_FALSE; } @@ -2044,7 +2126,7 @@ PHP_METHOD(Memcached, resetServerList) MEMC_METHOD_FETCH_OBJECT; - memcached_servers_reset(m_obj->memc); + memcached_servers_reset(intern->memc); RETURN_TRUE; } /* }}} */ @@ -2061,7 +2143,7 @@ PHP_METHOD(Memcached, quit) MEMC_METHOD_FETCH_OBJECT; - memcached_quit(m_obj->memc); + memcached_quit(intern->memc); RETURN_TRUE; } /* }}} */ @@ -2077,7 +2159,7 @@ PHP_METHOD(Memcached, flushBuffers) } MEMC_METHOD_FETCH_OBJECT; - RETURN_BOOL(memcached_flush_buffers(m_obj->memc) == MEMCACHED_SUCCESS); + RETURN_BOOL(memcached_flush_buffers(intern->memc) == MEMCACHED_SUCCESS); } /* }}} */ @@ -2094,7 +2176,7 @@ PHP_METHOD(Memcached, getLastErrorMessage) MEMC_METHOD_FETCH_OBJECT; - RETURN_STRING(memcached_last_error_message(m_obj->memc)); + RETURN_STRING(memcached_last_error_message(intern->memc)); } /* }}} */ @@ -2110,7 +2192,7 @@ PHP_METHOD(Memcached, getLastErrorCode) MEMC_METHOD_FETCH_OBJECT; - RETURN_LONG(memcached_last_error(m_obj->memc)); + RETURN_LONG(memcached_last_error(intern->memc)); } /* }}} */ @@ -2126,7 +2208,7 @@ PHP_METHOD(Memcached, getLastErrorErrno) MEMC_METHOD_FETCH_OBJECT; - RETURN_LONG(memcached_last_error_errno(m_obj->memc)); + RETURN_LONG(memcached_last_error_errno(intern->memc)); } /* }}} */ #endif @@ -2145,7 +2227,7 @@ PHP_METHOD(Memcached, getLastDisconnectedServer) MEMC_METHOD_FETCH_OBJECT; - server_instance = memcached_server_get_last_disconnect(m_obj->memc); + server_instance = memcached_server_get_last_disconnect(intern->memc); if (server_instance == NULL) { RETURN_FALSE; } @@ -2156,14 +2238,81 @@ PHP_METHOD(Memcached, getLastDisconnectedServer) } /* }}} */ +#include + +static +zend_bool s_long_value(const char *str, zend_long *value) +{ + char *end = (char *) str; + + errno = 0; + *value = strtol(str, &end, 10); + + if (errno || str == end || *end != '\0') { + return 0; + } + return 1; +} + +static +zend_bool s_double_value(const char *str, double *value) +{ + char *end = (char *) str; + + errno = 0; + *value = strtod(str, &end); + + if (errno || str == end || *end != '\0') { + return 0; + } + return 1; +} + +static +memcached_return s_stat_execute_cb (php_memcached_instance_st instance, const char *key, size_t key_length, const char *value, size_t value_length, void *context) +{ + char *server_key; + size_t server_key_len; + zend_long long_val; + double d_val; + char *buffer; + + zval *return_value = (zval *) context; + zval *server_values; + + server_key_len = spprintf (&server_key, 0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance)); + server_values = zend_hash_str_find(Z_ARRVAL_P(return_value), server_key, server_key_len); + + if (!server_values) { + zval zv; + array_init(&zv); + + server_values = &zv; + add_assoc_zval_ex(return_value, server_key, server_key_len, server_values); + } + + spprintf (&buffer, 0, "%.*s", value_length, value); + + /* Check type */ + if (s_long_value (buffer, &long_val)) { + add_assoc_long(server_values, key, long_val); + } + else if (s_double_value (buffer, &d_val)) { + add_assoc_double(server_values, key, d_val); + } + else { + add_assoc_stringl_ex(server_values, key, key_length, value, value_length); + } + efree (buffer); + efree (server_key); + return MEMCACHED_SUCCESS; +} + /* {{{ Memcached::getStats() Returns statistics for the memcache servers */ PHP_METHOD(Memcached, getStats) { - memcached_stat_st *stats; memcached_return status; - struct callbackContext context = {0}; - memcached_server_function callbacks[1]; MEMC_METHOD_INIT_VARS; if (zend_parse_parameters_none() == FAILURE) { @@ -2172,29 +2321,12 @@ PHP_METHOD(Memcached, getStats) MEMC_METHOD_FETCH_OBJECT; - if (memcached_server_count(m_obj->memc) == 0) { - array_init(return_value); - return; - } - - stats = memcached_stat(m_obj->memc, NULL, &status); - php_memc_handle_error(i_obj, status); - if (stats == NULL) { - RETURN_FALSE; - } else if (status != MEMCACHED_SUCCESS && status != MEMCACHED_SOME_ERRORS) { - memcached_stat_free(m_obj->memc, stats); + array_init(return_value); + status = memcached_stat_execute(intern->memc, NULL, s_stat_execute_cb, return_value); + if (php_memc_handle_error(intern, status) < 0) { + zval_ptr_dtor(return_value); RETURN_FALSE; } - - array_init(return_value); - - callbacks[0] = php_memc_do_stats_callback; - context.i = 0; - context.stats = stats; - context.return_value = return_value; - memcached_server_cursor(m_obj->memc, callbacks, &context, 1); - - memcached_stat_free(m_obj->memc, stats); } /* }}} */ @@ -2202,8 +2334,7 @@ PHP_METHOD(Memcached, getStats) Returns the version of each memcached server in the pool */ PHP_METHOD(Memcached, getVersion) { - memcached_return status = MEMCACHED_SUCCESS; - struct callbackContext context = {0}; + memcached_return rc; memcached_server_function callbacks[1]; MEMC_METHOD_INIT_VARS; @@ -2213,28 +2344,29 @@ PHP_METHOD(Memcached, getVersion) MEMC_METHOD_FETCH_OBJECT; - array_init(return_value); - - status = memcached_version(m_obj->memc); - if (php_memc_handle_error(i_obj, status) < 0) { - zval_dtor(return_value); + rc = memcached_version(intern->memc); + if (php_memc_handle_error(intern, rc) < 0) { RETURN_FALSE; } - callbacks[0] = php_memc_do_version_callback; - context.return_value = return_value; + callbacks[0] = s_server_cursor_version_cb; - memcached_server_cursor(m_obj->memc, callbacks, &context, 1); + array_init(return_value); + rc = memcached_server_cursor(intern->memc, callbacks, return_value, 1); + if (php_memc_handle_error(intern, rc) < 0) { + zval_dtor(return_value); + RETURN_FALSE; + } } /* }}} */ /* {{{ Memcached::getAllKeys() Returns the keys stored on all the servers */ -static memcached_return php_memc_dump_func_callback(const memcached_st *ptr __attribute__((unused)), \ - const char *key, size_t key_length, void *context) +static +memcached_return s_dump_keys_cb(const memcached_st *ptr, const char *key, size_t key_length, void *in_context) { - zval *ctx = (zval*) context; - add_next_index_string(ctx, (char*) key); + zval *return_value = (zval*) in_context; + add_next_index_stringl(return_value, key, key_length); return MEMCACHED_SUCCESS; } @@ -2245,12 +2377,17 @@ PHP_METHOD(Memcached, getAllKeys) memcached_dump_func callback[1]; MEMC_METHOD_INIT_VARS; - callback[0] = php_memc_dump_func_callback; + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + callback[0] = s_dump_keys_cb; MEMC_METHOD_FETCH_OBJECT; array_init(return_value); - rc = memcached_dump(m_obj->memc, callback, return_value, 1); - if (php_memc_handle_error(i_obj, rc) < 0) { + + rc = memcached_dump(intern->memc, callback, return_value, 1); + if (php_memc_handle_error(intern, rc) < 0) { zval_dtor(return_value); RETURN_FALSE; } @@ -2270,10 +2407,10 @@ static PHP_METHOD(Memcached, flush) } MEMC_METHOD_FETCH_OBJECT; - i_obj->rescode = MEMCACHED_SUCCESS; + intern->rescode = MEMCACHED_SUCCESS; - status = memcached_flush(m_obj->memc, delay); - if (php_memc_handle_error(i_obj, status) < 0) { + status = memcached_flush(intern->memc, delay); + if (php_memc_handle_error(intern, status) < 0) { RETURN_FALSE; } @@ -2298,17 +2435,17 @@ static PHP_METHOD(Memcached, getOption) switch (option) { case MEMC_OPT_COMPRESSION_TYPE: - RETURN_LONG(m_obj->compression_type); + RETURN_LONG(memc_user_data->compression_type); case MEMC_OPT_COMPRESSION: - RETURN_BOOL(m_obj->compression); + RETURN_BOOL(memc_user_data->compression); case MEMC_OPT_PREFIX_KEY: { memcached_return retval; char *result; - result = memcached_callback_get(m_obj->memc, MEMCACHED_CALLBACK_PREFIX_KEY, &retval); + result = memcached_callback_get(intern->memc, MEMCACHED_CALLBACK_PREFIX_KEY, &retval); if (retval == MEMCACHED_SUCCESS && result) { #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX == 0x00049000 RETURN_STRINGL(result, strlen(result)); @@ -2321,20 +2458,20 @@ static PHP_METHOD(Memcached, getOption) } case MEMC_OPT_SERIALIZER: - RETURN_LONG((long)m_obj->serializer); + RETURN_LONG((long)memc_user_data->serializer); break; case MEMC_OPT_USER_FLAGS: - RETURN_LONG(m_obj->set_udf_flags); + RETURN_LONG(memc_user_data->set_udf_flags); break; case MEMC_OPT_STORE_RETRY_COUNT: - RETURN_LONG((long)m_obj->store_retry_count); + RETURN_LONG((long)memc_user_data->store_retry_count); break; case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE: case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE: - if (memcached_server_count(m_obj->memc) == 0) { + if (memcached_server_count(intern->memc) == 0) { php_error_docref(NULL, E_WARNING, "no servers defined"); return; } @@ -2344,32 +2481,33 @@ static PHP_METHOD(Memcached, getOption) * Assume that it's a libmemcached behavior option. */ flag = (memcached_behavior) option; - result = memcached_behavior_get(m_obj->memc, flag); + result = memcached_behavior_get(intern->memc, flag); RETURN_LONG((long)result); } } /* }}} */ -static int php_memc_set_option(php_memc_t *i_obj, long option, zval *value) +static +int php_memc_set_option(php_memc_object_t *intern, long option, zval *value) { memcached_return rc = MEMCACHED_FAILURE; memcached_behavior flag; - struct memc_obj *m_obj = i_obj->obj; + php_memc_user_data_t *memc_user_data = memcached_get_user_data(intern->memc); switch (option) { case MEMC_OPT_COMPRESSION: convert_to_long(value); - m_obj->compression = Z_LVAL_P(value) ? 1 : 0; + memc_user_data->compression = Z_LVAL_P(value) ? 1 : 0; break; case MEMC_OPT_COMPRESSION_TYPE: convert_to_long(value); if (Z_LVAL_P(value) == COMPRESSION_TYPE_FASTLZ || Z_LVAL_P(value) == COMPRESSION_TYPE_ZLIB) { - m_obj->compression_type = Z_LVAL_P(value); + memc_user_data->compression_type = Z_LVAL_P(value); } else { /* invalid compression type */ - i_obj->rescode = MEMCACHED_INVALID_ARGUMENTS; + intern->rescode = MEMCACHED_INVALID_ARGUMENTS; return 0; } break; @@ -2395,8 +2533,8 @@ static int php_memc_set_option(php_memc_t *i_obj, long option, zval *value) key = Z_STRVAL_P(value); #endif } - if (memcached_callback_set(m_obj->memc, MEMCACHED_CALLBACK_PREFIX_KEY, key) == MEMCACHED_BAD_KEY_PROVIDED) { - i_obj->rescode = MEMCACHED_INVALID_ARGUMENTS; + if (memcached_callback_set(intern->memc, MEMCACHED_CALLBACK_PREFIX_KEY, key) == MEMCACHED_BAD_KEY_PROVIDED) { + intern->rescode = MEMCACHED_INVALID_ARGUMENTS; php_error_docref(NULL, E_WARNING, "bad key provided"); return 0; } @@ -2407,10 +2545,10 @@ static int php_memc_set_option(php_memc_t *i_obj, long option, zval *value) flag = (memcached_behavior) option; convert_to_long(value); - rc = memcached_behavior_set(m_obj->memc, flag, (uint64_t) Z_LVAL_P(value)); + rc = memcached_behavior_set(intern->memc, flag, (uint64_t) Z_LVAL_P(value)); - if (php_memc_handle_error(i_obj, rc) < 0) { - php_error_docref(NULL, E_WARNING, "error setting memcached option: %s", memcached_strerror (m_obj->memc, rc)); + if (php_memc_handle_error(intern, rc) < 0) { + php_error_docref(NULL, E_WARNING, "error setting memcached option: %s", memcached_strerror (intern->memc, rc)); return 0; } @@ -2421,12 +2559,12 @@ static int php_memc_set_option(php_memc_t *i_obj, long option, zval *value) */ if (!Z_LVAL_P(value)) { #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX > 0x00037000 - (void)memcached_behavior_set_key_hash(m_obj->memc, MEMCACHED_HASH_DEFAULT); - (void)memcached_behavior_set_distribution_hash(m_obj->memc, MEMCACHED_HASH_DEFAULT); - (void)memcached_behavior_set_distribution(m_obj->memc, MEMCACHED_DISTRIBUTION_MODULA); + (void)memcached_behavior_set_key_hash(intern->memc, MEMCACHED_HASH_DEFAULT); + (void)memcached_behavior_set_distribution_hash(intern->memc, MEMCACHED_HASH_DEFAULT); + (void)memcached_behavior_set_distribution(intern->memc, MEMCACHED_DISTRIBUTION_MODULA); #else - m_obj->memc->hash = 0; - m_obj->memc->distribution = 0; + intern->memc->hash = 0; + intern->memc->distribution = 0; #endif } break; @@ -2437,28 +2575,28 @@ static int php_memc_set_option(php_memc_t *i_obj, long option, zval *value) /* igbinary serializer */ #ifdef HAVE_MEMCACHED_IGBINARY if (Z_LVAL_P(value) == SERIALIZER_IGBINARY) { - m_obj->serializer = SERIALIZER_IGBINARY; + memc_user_data->serializer = SERIALIZER_IGBINARY; } else #endif #ifdef HAVE_JSON_API if (Z_LVAL_P(value) == SERIALIZER_JSON) { - m_obj->serializer = SERIALIZER_JSON; + memc_user_data->serializer = SERIALIZER_JSON; } else if (Z_LVAL_P(value) == SERIALIZER_JSON_ARRAY) { - m_obj->serializer = SERIALIZER_JSON_ARRAY; + memc_user_data->serializer = SERIALIZER_JSON_ARRAY; } else #endif /* msgpack serializer */ #ifdef HAVE_MEMCACHED_MSGPACK if (Z_LVAL_P(value) == SERIALIZER_MSGPACK) { - m_obj->serializer = SERIALIZER_MSGPACK; + memc_user_data->serializer = SERIALIZER_MSGPACK; } else #endif /* php serializer */ if (Z_LVAL_P(value) == SERIALIZER_PHP) { - m_obj->serializer = SERIALIZER_PHP; + memc_user_data->serializer = SERIALIZER_PHP; } else { - m_obj->serializer = SERIALIZER_PHP; - i_obj->rescode = MEMCACHED_INVALID_ARGUMENTS; + memc_user_data->serializer = SERIALIZER_PHP; + intern->rescode = MEMCACHED_INVALID_ARGUMENTS; php_error_docref(NULL, E_WARNING, "invalid serializer provided"); return 0; } @@ -2469,7 +2607,7 @@ static int php_memc_set_option(php_memc_t *i_obj, long option, zval *value) convert_to_long(value); if (Z_LVAL_P(value) < 0) { - m_obj->set_udf_flags = -1; + memc_user_data->set_udf_flags = -1; return 1; } @@ -2477,12 +2615,12 @@ static int php_memc_set_option(php_memc_t *i_obj, long option, zval *value) php_error_docref(NULL, E_WARNING, "MEMC_OPT_USER_FLAGS must be < %u", MEMC_VAL_USER_FLAGS_MAX); return 0; } - m_obj->set_udf_flags = Z_LVAL_P(value); + memc_user_data->set_udf_flags = Z_LVAL_P(value); break; case MEMC_OPT_STORE_RETRY_COUNT: convert_to_long(value); - m_obj->store_retry_count = Z_LVAL_P(value); + memc_user_data->store_retry_count = Z_LVAL_P(value); break; default: @@ -2497,15 +2635,15 @@ static int php_memc_set_option(php_memc_t *i_obj, long option, zval *value) convert_to_long(value); if (flag < MEMCACHED_BEHAVIOR_MAX) { - rc = memcached_behavior_set(m_obj->memc, flag, (uint64_t) Z_LVAL_P(value)); + rc = memcached_behavior_set(intern->memc, flag, (uint64_t) Z_LVAL_P(value)); } else { rc = MEMCACHED_INVALID_ARGUMENTS; } } - if (php_memc_handle_error(i_obj, rc) < 0) { - php_error_docref(NULL, E_WARNING, "error setting memcached option: %s", memcached_strerror (m_obj->memc, rc)); + if (php_memc_handle_error(intern, rc) < 0) { + php_error_docref(NULL, E_WARNING, "error setting memcached option: %s", memcached_strerror (intern->memc, rc)); return 0; } break; @@ -2601,9 +2739,9 @@ PHP_METHOD(Memcached, setBucket) } } - rc = memcached_bucket_set (m_obj->memc, server_map, forward_map, (uint32_t) server_map_len, replicas); + rc = memcached_bucket_set (intern->memc, server_map, forward_map, (uint32_t) server_map_len, replicas); - if (php_memc_handle_error(i_obj, rc) < 0) { + if (php_memc_handle_error(intern, rc) < 0) { retval = 0;; } @@ -2642,7 +2780,7 @@ static PHP_METHOD(Memcached, setOptions) zval copy; ZVAL_DUP(©, value); - if (!php_memc_set_option(i_obj, (long) key_index, ©)) { + if (!php_memc_set_option(intern, (long) key_index, ©)) { ok = 0; } @@ -2668,7 +2806,7 @@ static PHP_METHOD(Memcached, setOption) MEMC_METHOD_FETCH_OBJECT; - RETURN_BOOL(php_memc_set_option(i_obj, option, value)); + RETURN_BOOL(php_memc_set_option(intern, option, value)); } /* }}} */ @@ -2692,14 +2830,14 @@ static PHP_METHOD(Memcached, setSaslAuthData) MEMC_METHOD_FETCH_OBJECT; - if (!memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) { + if (!memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) { php_error_docref(NULL, E_WARNING, "SASL is only supported with binary protocol"); RETURN_FALSE; } - m_obj->has_sasl_data = 1; - status = memcached_set_sasl_auth_data(m_obj->memc, user->val, pass->val); + memc_user_data->has_sasl_data = 1; + status = memcached_set_sasl_auth_data(intern->memc, user->val, pass->val); - if (php_memc_handle_error(i_obj, status) < 0) { + if (php_memc_handle_error(intern, status) < 0) { RETURN_FALSE; } RETURN_TRUE; @@ -2719,7 +2857,7 @@ static PHP_METHOD(Memcached, getResultCode) MEMC_METHOD_FETCH_OBJECT; - RETURN_LONG(i_obj->rescode); + RETURN_LONG(intern->rescode); } /* }}} */ @@ -2735,7 +2873,7 @@ static PHP_METHOD(Memcached, getResultMessage) MEMC_METHOD_FETCH_OBJECT; - switch (i_obj->rescode) { + switch (intern->rescode) { case MEMC_RES_PAYLOAD_FAILURE: RETURN_STRING("PAYLOAD FAILURE"); break; @@ -2743,14 +2881,14 @@ static PHP_METHOD(Memcached, getResultMessage) case MEMCACHED_ERRNO: case MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE: case MEMCACHED_UNKNOWN_READ_FAILURE: - if (i_obj->memc_errno) { + if (intern->memc_errno) { zend_string *str = strpprintf(0, "%s: %s", - memcached_strerror(m_obj->memc, (memcached_return)i_obj->rescode), strerror(i_obj->memc_errno)); + memcached_strerror(intern->memc, (memcached_return)intern->rescode), strerror(intern->memc_errno)); RETURN_STR(str); } /* Fall through */ default: - RETURN_STRING(memcached_strerror(m_obj->memc, (memcached_return)i_obj->rescode)); + RETURN_STRING(memcached_strerror(intern->memc, (memcached_return)intern->rescode)); break; } @@ -2769,7 +2907,7 @@ static PHP_METHOD(Memcached, isPersistent) MEMC_METHOD_FETCH_OBJECT; - RETURN_BOOL(i_obj->is_persistent); + RETURN_BOOL(memc_user_data->is_persistent); } /* }}} */ @@ -2785,7 +2923,7 @@ static PHP_METHOD(Memcached, isPristine) MEMC_METHOD_FETCH_OBJECT; - RETURN_BOOL(i_obj->is_pristine); + RETURN_BOOL(intern->is_pristine); } /* }}} */ @@ -2794,40 +2932,47 @@ static PHP_METHOD(Memcached, isPristine) ****************************************/ /* {{{ constructor/destructor */ -static void php_memc_destroy(struct memc_obj *m_obj, zend_bool persistent) +static +void php_memc_destroy(memcached_st *memc, php_memc_user_data_t *memc_user_data) { #if HAVE_MEMCACHED_SASL - if (m_obj->has_sasl_data) { - memcached_destroy_sasl_auth_data(m_obj->memc); + if (memc_user_data->has_sasl_data) { + memcached_destroy_sasl_auth_data(memc); } #endif - if (m_obj->memc) { - memcached_free(m_obj->memc); - } - pefree(m_obj, persistent); + + memcached_set_memory_allocators(memc, NULL, NULL, NULL, NULL, NULL); + memcached_free(memc); + pefree(memc_user_data, memc_user_data->is_persistent); } -static void php_memc_free_storage(zend_object *obj) +static +void php_memc_object_free_storage(zend_object *object) { - php_memc_t *i_obj = php_memc_fetch_object(obj); + php_memc_object_t *intern = php_memc_fetch_object(object); - if (i_obj->obj && !i_obj->is_persistent) { - php_memc_destroy(i_obj->obj, 0); + if (intern->memc) { + php_memc_user_data_t *memc_user_data = memcached_get_user_data(intern->memc); + + if (!memc_user_data->is_persistent) { + php_memc_destroy(intern->memc, memc_user_data); + } } - zend_object_std_dtor(&i_obj->zo); - i_obj->obj = NULL; + + intern->memc = NULL; + zend_object_std_dtor(&intern->zo); } -static zend_object *php_memc_new(zend_class_entry *ce) +static +zend_object *php_memc_object_new(zend_class_entry *ce) { - php_memc_t *i_obj = ecalloc(1, sizeof(php_memc_t) + zend_object_properties_size(ce)); - - zend_object_std_init(&i_obj->zo, ce); - object_properties_init(&i_obj->zo, ce); - - i_obj->zo.handlers = &memcached_object_handlers; - - return &i_obj->zo; + php_memc_object_t *intern = ecalloc(1, sizeof(php_memc_object_t) + zend_object_properties_size(ce)); + + zend_object_std_init(&intern->zo, ce); + object_properties_init(&intern->zo, ce); + + intern->zo.handlers = &memcached_object_handlers; + return &intern->zo; } #ifdef HAVE_MEMCACHED_PROTOCOL @@ -2860,8 +3005,8 @@ zend_object_value php_memc_server_new(zend_class_entry *ce) ZEND_RSRC_DTOR_FUNC(php_memc_dtor) { if (res->ptr) { - struct memc_obj *m_obj = (struct memc_obj *)res->ptr; - php_memc_destroy(m_obj, 1); + memcached_st *memc = (memcached_st *) res->ptr; + php_memc_destroy(memc, memcached_get_user_data(memc)); res->ptr = NULL; } } @@ -2869,92 +3014,54 @@ ZEND_RSRC_DTOR_FUNC(php_memc_dtor) /* }}} */ /* {{{ internal API functions */ -static memcached_return php_memc_do_serverlist_callback(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context) +static +memcached_return s_server_cursor_list_servers_cb(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context) { - struct callbackContext* context = (struct callbackContext*) in_context; zval array; + zval *return_value = (zval *) in_context; array_init(&array); - add_assoc_string(&array, "host", (char*) memcached_server_name(instance)); - add_assoc_long(&array, "port", memcached_server_port(instance)); + add_assoc_string(&array, "host", memcached_server_name(instance)); + add_assoc_long(&array, "port", memcached_server_port(instance)); + add_assoc_string(&array, "type", memcached_server_type(instance)); /* * API does not allow to get at this field. add_assoc_long(array, "weight", instance->weight); */ - add_next_index_zval(context->return_value, &array); + add_next_index_zval(return_value, &array); return MEMCACHED_SUCCESS; } -static memcached_return php_memc_do_stats_callback(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context) +static +memcached_return s_server_cursor_version_cb(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context) { - char *hostport = NULL; - int hostport_len; - struct callbackContext* context = (struct callbackContext*) in_context; - zval entry; - hostport_len = spprintf(&hostport, 0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance)); - - array_init(&entry); - - add_assoc_long(&entry, "pid", context->stats[context->i].pid); - add_assoc_long(&entry, "uptime", context->stats[context->i].uptime); - add_assoc_long(&entry, "threads", context->stats[context->i].threads); - add_assoc_long(&entry, "time", context->stats[context->i].time); - add_assoc_long(&entry, "pointer_size", context->stats[context->i].pointer_size); - add_assoc_long(&entry, "rusage_user_seconds", context->stats[context->i].rusage_user_seconds); - add_assoc_long(&entry, "rusage_user_microseconds", context->stats[context->i].rusage_user_microseconds); - add_assoc_long(&entry, "rusage_system_seconds", context->stats[context->i].rusage_system_seconds); - add_assoc_long(&entry, "rusage_system_microseconds", context->stats[context->i].rusage_system_microseconds); - add_assoc_long(&entry, "curr_items", context->stats[context->i].curr_items); - add_assoc_long(&entry, "total_items", context->stats[context->i].total_items); - add_assoc_long(&entry, "limit_maxbytes", context->stats[context->i].limit_maxbytes); - add_assoc_long(&entry, "curr_connections", context->stats[context->i].curr_connections); - add_assoc_long(&entry, "total_connections", context->stats[context->i].total_connections); - add_assoc_long(&entry, "connection_structures", context->stats[context->i].connection_structures); - add_assoc_long(&entry, "bytes", context->stats[context->i].bytes); - add_assoc_long(&entry, "cmd_get", context->stats[context->i].cmd_get); - add_assoc_long(&entry, "cmd_set", context->stats[context->i].cmd_set); - add_assoc_long(&entry, "get_hits", context->stats[context->i].get_hits); - add_assoc_long(&entry, "get_misses", context->stats[context->i].get_misses); - add_assoc_long(&entry, "evictions", context->stats[context->i].evictions); - add_assoc_long(&entry, "bytes_read", context->stats[context->i].bytes_read); - add_assoc_long(&entry, "bytes_written", context->stats[context->i].bytes_written); - add_assoc_stringl(&entry, "version", context->stats[context->i].version, strlen(context->stats[context->i].version)); - - add_assoc_zval_ex(context->return_value, hostport, hostport_len, &entry); - efree(hostport); - - /* Increment the server count in our context structure. Failure to do so will cause only the stats for the last server to get displayed. */ - context->i++; - return MEMCACHED_SUCCESS; -} + char *address, *version; + size_t address_len, version_len; -static memcached_return php_memc_do_version_callback(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context) -{ - char *hostport = NULL; - char version[16]; - int hostport_len, version_len; - struct callbackContext* context = (struct callbackContext*) in_context; + zval *return_value = (zval *) in_context; - hostport_len = spprintf(&hostport, 0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance) - 1); #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x01000009 - version_len = snprintf(version, sizeof(version), "%d.%d.%d", + version_len = spprintf(&version, sizeof(version), "%d.%d.%d", memcached_server_major_version(instance), memcached_server_minor_version(instance), memcached_server_micro_version(instance)); #else - version_len = snprintf(version, sizeof(version), "%d.%d.%d", + version_len = spprintf(&version, sizeof(version) - 1, "%d.%d.%d", instance->major_version, instance->minor_version, instance->micro_version); #endif - add_assoc_stringl_ex(context->return_value, hostport, hostport_len, version, version_len); - efree(hostport); + address_len = spprintf(&address, 0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance) - 1); + add_assoc_stringl_ex(return_value, address, address_len, version, version_len); + + efree(address); + efree(version); return MEMCACHED_SUCCESS; } -static int php_memc_handle_error(php_memc_t *i_obj, memcached_return status) +static int php_memc_handle_error(php_memc_object_t *intern, memcached_return status) { int result = 0; @@ -2964,35 +3071,25 @@ static int php_memc_handle_error(php_memc_t *i_obj, memcached_return status) case MEMCACHED_DELETED: case MEMCACHED_STAT: result = 0; - i_obj->memc_errno = 0; + intern->memc_errno = 0; break; case MEMCACHED_END: case MEMCACHED_BUFFERED: - i_obj->rescode = status; - i_obj->memc_errno = 0; + intern->rescode = status; + intern->memc_errno = 0; result = 0; break; case MEMCACHED_SOME_ERRORS: - i_obj->rescode = status; -#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x00049000 - i_obj->memc_errno = memcached_last_error_errno(i_obj->obj->memc); -#else - i_obj->memc_errno = i_obj->obj->memc->cached_errno; /* Hnngghgh! */ - -#endif + intern->rescode = status; + intern->memc_errno = memcached_last_error_errno(intern->memc); result = 0; break; default: - i_obj->rescode = status; -#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x00049000 - i_obj->memc_errno = memcached_last_error_errno(i_obj->obj->memc); -#else - i_obj->memc_errno = i_obj->obj->memc->cached_errno; /* Hnngghgh! */ - -#endif + intern->rescode = status; + intern->memc_errno = memcached_last_error_errno(intern->memc); result = -1; break; } @@ -3443,94 +3540,87 @@ zend_class_entry *php_memc_get_exception_base(int root) #endif } -static memcached_return php_memc_do_cache_callback(zval *zmemc_obj, zend_fcall_info *fci, - zend_fcall_info_cache *fcc, zend_string *key, zval *value) +static +memcached_return s_invoke_cache_callback(zval *zobject, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string *key, zval *value) { - zend_string *payload = NULL; + memcached_return rc = MEMCACHED_SUCCESS; + int result; + zval params[4]; zval retval; - zval z_key; - zval z_val; - zval *expiration, z_expiration; + zval zv_key, ref_val; + zval ref_expiration, zv_expiration; - uint32_t flags = 0; - memcached_return rc; - php_memc_t* i_obj; - memcached_return status = MEMCACHED_SUCCESS; - int result; + /* Prepare params */ + ZVAL_STR(&zv_key, key); + + ZVAL_NULL(&ref_val); + ZVAL_NULL(&zv_expiration); - ZVAL_STR(&z_key, key); - ZVAL_NULL(&z_val); - ZVAL_NEW_REF(&z_val, value); - ZVAL_NEW_REF(&z_expiration, value); - ZVAL_LONG(Z_REFVAL(z_expiration), 0); + ZVAL_NEW_REF(&ref_val, value); + ZVAL_NEW_REF(&ref_expiration, &zv_expiration); - ZVAL_COPY(¶ms[0], zmemc_obj); - ZVAL_COPY(¶ms[1], &z_key); - ZVAL_COPY_VALUE(¶ms[2], &z_val); - ZVAL_COPY_VALUE(¶ms[3], &z_expiration); + ZVAL_COPY(¶ms[0], zobject); + ZVAL_COPY(¶ms[1], &zv_key); + ZVAL_COPY_VALUE(¶ms[2], &ref_val); + ZVAL_COPY_VALUE(¶ms[3], &ref_expiration); fci->retval = &retval; fci->params = params; fci->param_count = 4; result = zend_call_function(fci, fcc); + ZVAL_DUP(value, Z_REFVAL(ref_val)); - ZVAL_DUP(value, Z_REFVAL(z_val)); - expiration = Z_REFVAL(z_expiration); if (result == SUCCESS && Z_TYPE(retval) != IS_UNDEF) { - struct memc_obj *m_obj; - i_obj = Z_MEMC_OBJ_P(zmemc_obj) - m_obj = i_obj->obj; if (zend_is_true(&retval)) { - time_t expir; + time_t expiration; + zend_string *payload; + uint32_t flags = 0; + php_memc_object_t *intern; + php_memc_user_data_t *memc_user_data; - expir = zval_get_long(expiration); - payload = s_zval_to_payload(value, &flags, m_obj->serializer, m_obj->compression_type); + intern = Z_MEMC_OBJ_P(zobject); + memc_user_data = memcached_get_user_data(intern->memc); + + expiration = zval_get_long(Z_REFVAL(ref_expiration)); + payload = s_zval_to_payload(value, &flags, memc_user_data->serializer, memc_user_data->compression_type); if (payload == NULL) { - status = (memcached_return)MEMC_RES_PAYLOAD_FAILURE; + rc = (memcached_return) MEMC_RES_PAYLOAD_FAILURE; } else { - if (m_obj->set_udf_flags >= 0) { - MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) m_obj->set_udf_flags)); + if (memc_user_data->set_udf_flags >= 0) { + MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) memc_user_data->set_udf_flags)); } - rc = memcached_set(m_obj->memc, key->val, key->len, payload->val, payload->len, expir, flags); - if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED) { - status = rc; + rc = memcached_set(intern->memc, key->val, key->len, payload->val, payload->len, expiration, flags); + if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_BUFFERED) { + rc = MEMCACHED_SOME_ERRORS; } zend_string_release(payload); } } else { - status = MEMCACHED_NOTFOUND; + rc = MEMCACHED_NOTFOUND; zval_dtor(value); ZVAL_NULL(value); } - - } else { - if (result == FAILURE) { - php_error_docref(NULL, E_WARNING, "could not invoke cache callback"); - } - status = MEMCACHED_FAILURE; - zval_dtor(value); - ZVAL_NULL(value); } if (!Z_ISUNDEF(retval)) { zval_ptr_dtor(&retval); } - zval_ptr_dtor(&z_key); - zval_ptr_dtor(&z_val); - zval_ptr_dtor(&z_expiration); - zval_ptr_dtor(zmemc_obj); - - return status; + zval_ptr_dtor(&zv_key); + zval_ptr_dtor(&ref_val); + zval_ptr_dtor(&zv_expiration); + zval_ptr_dtor(&ref_expiration); + zval_ptr_dtor(zobject); + return rc; } -static int php_memc_do_result_callback(zval *zmemc_obj, zend_fcall_info *fci, - zend_fcall_info_cache *fcc, - memcached_result_st *result) + +static +int s_invoke_result_callback(zval *zmemc_obj, zend_fcall_info *fci, zend_fcall_info_cache *fcc, memcached_result_st *result) { const char *res_key = NULL; size_t res_key_len = 0; @@ -3542,7 +3632,7 @@ static int php_memc_do_result_callback(zval *zmemc_obj, zend_fcall_info *fci, zval z_result; uint32_t flags = 0; int rc = 0; - php_memc_t *i_obj = NULL; + php_memc_object_t *intern = NULL; fci->retval = &retval; fci->param_count = 2; @@ -3554,10 +3644,10 @@ static int php_memc_do_result_callback(zval *zmemc_obj, zend_fcall_info *fci, res_key_len = memcached_result_key_length(result); cas = memcached_result_cas(result); - i_obj = Z_MEMC_OBJ_P(zmemc_obj); + intern = Z_MEMC_OBJ_P(zmemc_obj); if (!s_memcached_result_to_zval(result, &value)) { - i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE; + intern->rescode = MEMC_RES_PAYLOAD_FAILURE; return -1; } @@ -4085,6 +4175,8 @@ PHP_GINIT_FUNCTION(php_memcached) php_memcached_globals->session_ini.sasl_username = NULL; php_memcached_globals->session_ini.sasl_password = NULL; + php_memcached_globals->no_effect = 0; + #endif php_memcached_globals->memc_ini.serializer_name = NULL; php_memcached_globals->memc_ini.serializer = SERIALIZER_DEFAULT; @@ -4362,15 +4454,15 @@ PHP_MINIT_FUNCTION(memcached) zend_class_entry ce; memcpy(&memcached_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); - memcached_object_handlers.offset = XtOffsetOf(php_memc_t, zo); + memcached_object_handlers.offset = XtOffsetOf(php_memc_object_t, zo); memcached_object_handlers.clone_obj = NULL; - memcached_object_handlers.free_obj = php_memc_free_storage; + memcached_object_handlers.free_obj = php_memc_object_free_storage; le_memc = zend_register_list_destructors_ex(NULL, php_memc_dtor, "Memcached persistent connection", module_number); INIT_CLASS_ENTRY(ce, "Memcached", memcached_class_methods); memcached_ce = zend_register_internal_class(&ce); - memcached_ce->create_object = php_memc_new; + memcached_ce->create_object = php_memc_object_new; #ifdef HAVE_MEMCACHED_PROTOCOL memcpy(&memcached_server_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); diff --git a/php_memcached_private.h b/php_memcached_private.h index 46565e70..4a4dc4fe 100644 --- a/php_memcached_private.h +++ b/php_memcached_private.h @@ -176,6 +176,9 @@ ZEND_BEGIN_MODULE_GLOBALS(php_memcached) } memc_ini; + /* For deprecated values */ + zend_long no_effect; + #ifdef HAVE_MEMCACHED_PROTOCOL struct { diff --git a/php_memcached_session.c b/php_memcached_session.c index 1a398ab7..34bfc77c 100644 --- a/php_memcached_session.c +++ b/php_memcached_session.c @@ -297,6 +297,8 @@ memcached_st *s_init_mod_data (const memcached_server_list_st servers, zend_bool memcached_set_user_data(memc, user_data); memcached_server_push (memc, servers); + + memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_VERIFY_KEY, 1); return memc; } @@ -501,6 +503,21 @@ PS_CREATE_SID_FUNC(memcached) sid = NULL; } } + + if (sid) { + if (sid->len + (sizeof ("lock.") - 1) > (MEMCACHED_MAX_KEY - 1)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session id is too long to be stored in memcached"); + zend_string_release (sid); + return NULL; + } + if (MEMC_SESS_STR_INI(prefix)) { + if (strlen (MEMC_SESS_STR_INI(prefix)) + sid->len + (sizeof ("lock.") - 1) > (MEMCACHED_MAX_KEY - 1)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session id with prefix is too long to be stored in memcached"); + zend_string_release (sid); + return NULL; + } + } + } return sid; } diff --git a/tests/bug_16084.phpt b/tests/bug_16084.phpt index c103b297..ba217a70 100644 --- a/tests/bug_16084.phpt +++ b/tests/bug_16084.phpt @@ -7,16 +7,14 @@ Memcached: Bug #16084 (Crash when addServers is called with an associative array $servers = array ( 0 => array ( 'KEYHERE' => 'localhost', 11211, 3 ), ); $m = new memcached(); var_dump($m->addServers($servers)); -var_dump($m->getServerList()); +$list = $m->getServerList(); + +var_dump ($list[0]["host"], $list[0]["port"]); +echo "OK"; + ?> --EXPECT-- bool(true) -array(1) { - [0]=> - array(2) { - ["host"]=> - string(9) "localhost" - ["port"]=> - int(11211) - } -} +string(9) "localhost" +int(11211) +OK diff --git a/tests/callback_exception.phpt b/tests/callback_exception.phpt index fa149077..176163e8 100644 --- a/tests/callback_exception.phpt +++ b/tests/callback_exception.phpt @@ -40,7 +40,7 @@ try { $m = new Memcached(null, 'throw_something'); echo "fail\n"; } catch (Exception $e) { - echo "fail\n"; + echo "success\n"; } echo "OK\n"; @@ -50,4 +50,5 @@ echo "OK\n"; success success empty_cb called +success OK diff --git a/tests/getserverlist.phpt b/tests/getserverlist.phpt index e4ef5968..88b7d27c 100644 --- a/tests/getserverlist.phpt +++ b/tests/getserverlist.phpt @@ -14,41 +14,52 @@ var_dump($m->getServerList()); $m = new memcached(); $m->addServer('127.0.0.1', 11211); var_dump($m->getServerList()); + +echo "OK"; ?> ---EXPECTF-- +--EXPECT-- array(0) { } array(1) { [0]=> - array(2) { + array(3) { ["host"]=> string(9) "localhost" ["port"]=> int(11211) + ["type"]=> + string(3) "TCP" } } array(2) { [0]=> - array(2) { + array(3) { ["host"]=> string(9) "localhost" ["port"]=> int(11211) + ["type"]=> + string(3) "TCP" } [1]=> - array(2) { + array(3) { ["host"]=> string(9) "localhost" ["port"]=> int(11211) + ["type"]=> + string(3) "TCP" } } array(1) { [0]=> - array(2) { + array(3) { ["host"]=> string(9) "127.0.0.1" ["port"]=> int(11211) + ["type"]=> + string(3) "TCP" } } +OK \ No newline at end of file diff --git a/tests/invoke_callback.phpt b/tests/invoke_callback.phpt index 55cbec1e..83e15ca2 100644 --- a/tests/invoke_callback.phpt +++ b/tests/invoke_callback.phpt @@ -12,6 +12,7 @@ function my_func(Memcached $obj, $persistent_id = null) $obj->addServer(MEMC_SERVER_HOST, MEMC_SERVER_PORT); } +$m = new Memcached('hi', 'my_func'); $m = new Memcached('hi', 'my_func'); var_dump($m->getServerList()); @@ -21,11 +22,13 @@ echo "OK\n"; --EXPECTF-- array(1) { [0]=> - array(2) { + array(3) { ["host"]=> string(9) "127.0.0.1" ["port"]=> int(11211) + ["type"]=> + string(3) "TCP" } } OK diff --git a/tests/keys.phpt b/tests/keys.phpt index 89632f5d..927dc507 100644 --- a/tests/keys.phpt +++ b/tests/keys.phpt @@ -11,6 +11,7 @@ $binary = memc_get_instance (array ( )); $ascii = memc_get_instance (); +$ascii->setOption(Memcached::OPT_VERIFY_KEY, 1); var_dump ($binary->set ('binary key with spaces', 'this is a test')); var_dump ($binary->getResultCode () == Memcached::RES_SUCCESS); diff --git a/tests/session_badconf_emptyprefix.phpt b/tests/session_badconf_emptyprefix.phpt index 74d681dd..825bb8e2 100644 --- a/tests/session_badconf_emptyprefix.phpt +++ b/tests/session_badconf_emptyprefix.phpt @@ -7,25 +7,22 @@ if (!Memcached::HAVE_SESSION) print "skip"; ?> --INI-- memcached.sess_locking = on -memcached.sess_lock_wait = 150000 memcached.sess_prefix = "memc.sess.key." -session.save_handler = memcached +session.save_handler = "memcached" --FILE-- --INI-- -memcached.sess_locking = on -memcached.sess_lock_wait = 150000 -memcached.sess_prefix = "memc.sess.key." session.save_handler = memcached - --FILE-- --INI-- -memcached.sess_locking = on -memcached.sess_lock_wait = 150000 -memcached.sess_prefix = "memc.sess.key." session.save_handler = memcached - --FILE-- --INI-- -memcached.sess_locking = on -memcached.sess_lock_wait = 150000 -memcached.sess_prefix = "memc.sess.key." session.save_handler = memcached - --FILE-- --INI-- -memcached.sess_locking = on -memcached.sess_lock_wait = 150000 -memcached.sess_prefix = "memc.sess.key." session.save_handler = memcached - --FILE-- TRUE]); $_SESSION['foo'] = 1; diff --git a/tests/session_basic3.phpt b/tests/session_basic3.phpt index b8e4f5f8..21288571 100644 --- a/tests/session_basic3.phpt +++ b/tests/session_basic3.phpt @@ -6,26 +6,24 @@ if (!extension_loaded("memcached")) print "skip"; if (!Memcached::HAVE_SESSION) print "skip"; ?> --INI-- -memcached.sess_locking = on -memcached.sess_lock_wait = 150000 -memcached.sess_prefix = "memc.sess.key." session.save_handler = memcached - --FILE-- TRUE]); +session_start(); $_SESSION['foo'] = 1; session_write_close(); $_SESSION = NULL; var_dump($_SESSION); -session_start(); +session_start([ + 'read_and_close' => true +]); var_dump($_SESSION); session_write_close(); From ecc7d8115191d2e42f8edbe28c819b899c1774f6 Mon Sep 17 00:00:00 2001 From: Mikko Date: Sun, 31 Jan 2016 16:11:05 +0000 Subject: [PATCH 055/104] Add tests, fix compilation error for non-sasl --- php_memcached.c | 2 ++ tests/get_flags.phpt | 65 +++++++++++++++++++++++++++++++++++ tests/session_lock.phpt | 58 +++++++++++++++++++++++++++++++ tests/session_regenerate.phpt | 26 ++++++++++++++ tests/stats.phpt | 23 +++++++++++++ 5 files changed, 174 insertions(+) create mode 100644 tests/get_flags.phpt create mode 100644 tests/session_lock.phpt create mode 100644 tests/session_regenerate.phpt create mode 100644 tests/stats.phpt diff --git a/php_memcached.c b/php_memcached.c index 1dbe0bab..dc7d2c28 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -323,7 +323,9 @@ PHP_INI_BEGIN() MEMC_INI_ENTRY("compression_factor", "1.3", OnUpdateReal, compression_factor) MEMC_INI_ENTRY("compression_threshold", "2000", OnUpdateLong, compression_threshold) MEMC_INI_ENTRY("serializer", SERIALIZER_DEFAULT_NAME, OnUpdateSerializer, serializer_name) +#if HAVE_MEMCACHED_SASL MEMC_INI_ENTRY("use_sasl", "0", OnUpdateBool, sasl_enabled) +#endif MEMC_INI_ENTRY("store_retry_count", "2", OnUpdateLong, store_retry_count) PHP_INI_END() /* }}} */ diff --git a/tests/get_flags.phpt b/tests/get_flags.phpt new file mode 100644 index 00000000..ef477fdc --- /dev/null +++ b/tests/get_flags.phpt @@ -0,0 +1,65 @@ +--TEST-- +Memcached::get/getMulti() flags +--SKIPIF-- + +--FILE-- +set ($key1, 'hello1', 20); +$m->set ($key2, 'hello2', 20); + +$value = $m->get($key1); +$extended = $m->get($key1, null, Memcached::GET_EXTENDED); + +var_dump ($value); +var_dump ($extended); + +$values = $m->getMulti(array ($key1, $key2), Memcached::GET_PRESERVE_ORDER); +$extended = $m->getMulti(array ($key1, $key2), Memcached::GET_EXTENDED | Memcached::GET_PRESERVE_ORDER); + +var_dump ($values); +var_dump ($extended); +echo "OK"; + +--EXPECTF-- +string(6) "hello1" +array(3) { + ["value"]=> + string(6) "hello1" + ["cas"]=> + int(%d) + ["flags"]=> + int(0) +} +array(2) { + ["memc.test.%s"]=> + string(6) "hello1" + ["memc.test.%s"]=> + string(6) "hello2" +} +array(2) { + ["memc.test.%s"]=> + array(3) { + ["value"]=> + string(6) "hello1" + ["cas"]=> + int(%d) + ["flags"]=> + int(0) + } + ["memc.test.%s"]=> + array(3) { + ["value"]=> + string(6) "hello2" + ["cas"]=> + int(%d) + ["flags"]=> + int(0) + } +} +OK \ No newline at end of file diff --git a/tests/session_lock.phpt b/tests/session_lock.phpt new file mode 100644 index 00000000..a328dd68 --- /dev/null +++ b/tests/session_lock.phpt @@ -0,0 +1,58 @@ +--TEST-- +Session lock +--SKIPIF-- + +--INI-- +memcached.sess_locking = true +memcached.sess_lock_wait_min = 500 +memcached.sess_lock_wait_max = 1000 +memcached.sess_lock_retries = 3 +memcached.sess_prefix = "memc.test." + +session.save_handler = memcached + +--FILE-- +addServer(MEMC_SERVER_HOST, MEMC_SERVER_PORT); + +ob_start(); +ini_set ('session.save_path', MEMC_SERVER_HOST . ':' . MEMC_SERVER_PORT); + +session_start(); +$session_id = session_id(); + +$_SESSION["test"] = "hello"; +session_write_close(); + +session_start(); +var_dump ($m->get ('memc.test.' . session_id())); +var_dump ($m->get ('memc.test.lock.' . session_id())); +session_write_close(); +var_dump ($m->get ('memc.test.lock.' . session_id())); + +// Test lock min / max +$m->set ('memc.test.lock.' . $session_id, '1'); + +$time_start = microtime(true); +session_start(); +$time = microtime(true) - $time_start; + +if (round ($time, 1) != 2.5) { + echo "Waited longer than expected: $time" . PHP_EOL; +} +echo "OK"; + +--EXPECTF-- +string(17) "test|s:5:"hello";" +string(1) "1" +bool(false) + +Warning: session_start(): Unable to clear session lock record in %s on line %d +OK diff --git a/tests/session_regenerate.phpt b/tests/session_regenerate.phpt new file mode 100644 index 00000000..794f46fc --- /dev/null +++ b/tests/session_regenerate.phpt @@ -0,0 +1,26 @@ +--TEST-- +Session regenerate +--SKIPIF-- + +--INI-- +session.save_handler = memcached +--FILE-- + +--FILE-- +getStats(); +$key = MEMC_SERVER_HOST . ':' . MEMC_SERVER_PORT; + +var_dump (count ($stats) === 1); +var_dump (isset ($stats[$key])); +var_dump (count ($stats[$key]) > 0); + +echo "OK"; +?> +--EXPECT-- +bool(true) +bool(true) +bool(true) +OK From 9ce59ef3c318e3c639c54cd433522834a436e56a Mon Sep 17 00:00:00 2001 From: Mikko Date: Sun, 31 Jan 2016 16:14:42 +0000 Subject: [PATCH 056/104] Add to package.xml --- package.xml | 4 ++++ tests/stats.phpt | 2 ++ 2 files changed, 6 insertions(+) diff --git a/package.xml b/package.xml index e42b8037..11879322 100644 --- a/package.xml +++ b/package.xml @@ -137,6 +137,10 @@ http://pear.php.net/dtd/package-2.0.xsd"> + + + + diff --git a/tests/stats.phpt b/tests/stats.phpt index ddd2ac4b..72b8014c 100644 --- a/tests/stats.phpt +++ b/tests/stats.phpt @@ -13,6 +13,7 @@ $key = MEMC_SERVER_HOST . ':' . MEMC_SERVER_PORT; var_dump (count ($stats) === 1); var_dump (isset ($stats[$key])); var_dump (count ($stats[$key]) > 0); +var_dump (is_int ($stats[$key]['cmd_get'])); echo "OK"; ?> @@ -20,4 +21,5 @@ echo "OK"; bool(true) bool(true) bool(true) +bool(true) OK From 782077ce575601855a169452a948077444d318e1 Mon Sep 17 00:00:00 2001 From: Mikko Date: Sun, 31 Jan 2016 23:11:11 +0000 Subject: [PATCH 057/104] Fix json serializer --- package.xml | 4 +- php_memcached.c | 187 ++++++++++++++++++------------------ php_memcached_private.h | 16 +-- php_memcached_session.c | 30 ++---- tests/types_json_multi.phpt | 2 +- 5 files changed, 112 insertions(+), 127 deletions(-) diff --git a/package.xml b/package.xml index 11879322..6c162a14 100644 --- a/package.xml +++ b/package.xml @@ -147,9 +147,7 @@ http://pear.php.net/dtd/package-2.0.xsd"> - 5.2.0 - 6.0.0 - 6.0.0 + 7.0.0 1.4.0b1 diff --git a/php_memcached.c b/php_memcached.c index dc7d2c28..cf8116a8 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -50,9 +50,9 @@ #endif #ifdef ZTS -#define MEMC_G(v) TSRMG(php_memcached_globals_id, zend_php_memcached_globals *, memc_ini.v) +#define MEMC_G(v) TSRMG(php_memcached_globals_id, zend_php_memcached_globals *, memc.v) #else -#define MEMC_G(v) (php_memcached_globals.memc_ini.v) +#define MEMC_G(v) (php_memcached_globals.memc.v) #endif #include @@ -285,10 +285,10 @@ PHP_INI_MH(OnUpdateSessionPrefixString) } #define MEMC_INI_ENTRY(key, default_value, update_fn, gkey) \ - STD_PHP_INI_ENTRY("memcached."key, default_value, PHP_INI_ALL, update_fn, memc_ini.gkey, zend_php_memcached_globals, php_memcached_globals) + STD_PHP_INI_ENTRY("memcached."key, default_value, PHP_INI_ALL, update_fn, memc.gkey, zend_php_memcached_globals, php_memcached_globals) #define MEMC_SESSION_INI_ENTRY(key, default_value, update_fn, gkey) \ - STD_PHP_INI_ENTRY("memcached.sess_"key, default_value, PHP_INI_ALL, update_fn, session_ini.gkey, zend_php_memcached_globals, php_memcached_globals) + STD_PHP_INI_ENTRY("memcached.sess_"key, default_value, PHP_INI_ALL, update_fn, session.gkey, zend_php_memcached_globals, php_memcached_globals) /* {{{ INI entries */ @@ -298,7 +298,7 @@ PHP_INI_BEGIN() MEMC_SESSION_INI_ENTRY("locking", "1", OnUpdateBool, lock_enabled) MEMC_SESSION_INI_ENTRY("lock_wait_min", "1000", OnUpdateLongGEZero, lock_wait_min) MEMC_SESSION_INI_ENTRY("lock_wait_max", "2000", OnUpdateLongGEZero, lock_wait_max) - MEMC_SESSION_INI_ENTRY("lock_retries", "5", OnUpdateLongGEZero, lock_retries) + MEMC_SESSION_INI_ENTRY("lock_retries", "5", OnUpdateLong, lock_retries) MEMC_SESSION_INI_ENTRY("lock_expire", "0", OnUpdateLongGEZero, lock_expiration) MEMC_SESSION_INI_ENTRY("compression", "1", OnUpdateBool, compression_enabled) MEMC_SESSION_INI_ENTRY("binary_protocol", "1", OnUpdateBool, binary_protocol_enabled) @@ -323,9 +323,6 @@ PHP_INI_BEGIN() MEMC_INI_ENTRY("compression_factor", "1.3", OnUpdateReal, compression_factor) MEMC_INI_ENTRY("compression_threshold", "2000", OnUpdateLong, compression_threshold) MEMC_INI_ENTRY("serializer", SERIALIZER_DEFAULT_NAME, OnUpdateSerializer, serializer_name) -#if HAVE_MEMCACHED_SASL - MEMC_INI_ENTRY("use_sasl", "0", OnUpdateBool, sasl_enabled) -#endif MEMC_INI_ENTRY("store_retry_count", "2", OnUpdateLong, store_retry_count) PHP_INI_END() /* }}} */ @@ -367,7 +364,7 @@ static void php_memc_destroy(memcached_st *memc, php_memc_user_data_t *memc_user_data); static - zend_bool s_memcached_result_to_zval(memcached_result_st *result, zval *return_value); + zend_bool s_memcached_result_to_zval(memcached_st *memc, memcached_result_st *result, zval *return_value); static zend_string *s_zval_to_payload(zval *value, uint32_t *flags, enum memcached_serializer serializer, enum memcached_compression_type compression_type); @@ -377,6 +374,24 @@ static Method implementations ****************************************/ +zend_bool php_memc_init_sasl_if_needed() +{ +#if HAVE_MEMCACHED_SASL + if (MEMC_G(sasl_initialised)) { + return 1; + } + if (sasl_client_init(NULL) != SASL_OK) { + php_error_docref(NULL, E_ERROR, "Failed to initialize SASL library"); + return 0; + } + return 1; +#else + php_error_docref(NULL, E_ERROR, "Memcached not built with sasl support"); + return 0; +#endif +} + + memcached_return php_memcached_exist (memcached_st *memc, zend_string *key) { @@ -816,7 +831,7 @@ memcached_return s_memcached_get_multi(memcached_st *memc, HashTable *hash_keys, } ZVAL_UNDEF(&value); - if (!s_memcached_result_to_zval(&result, &value)) { + if (!s_memcached_result_to_zval(memc, &result, &value)) { if (EG(exception)) { status = MEMC_RES_PAYLOAD_FAILURE; @@ -1136,9 +1151,9 @@ PHP_METHOD(Memcached, fetch) size_t res_key_len = 0; const char *payload = NULL; size_t payload_len = 0; - zval value; uint32_t flags = 0; uint64_t cas = 0; + zval value, zv_cas; memcached_result_st result; memcached_return status = MEMCACHED_SUCCESS; MEMC_METHOD_INIT_VARS; @@ -1157,29 +1172,25 @@ PHP_METHOD(Memcached, fetch) RETURN_FALSE; } - payload = memcached_result_value(&result); - payload_len = memcached_result_length(&result); - flags = memcached_result_flags(&result); - res_key = memcached_result_key_value(&result); - res_key_len = memcached_result_key_length(&result); - cas = memcached_result_cas(&result); - - if (!s_memcached_result_to_zval(&result, &value)) { + if (!s_memcached_result_to_zval(intern->memc, &result, &value)) { memcached_result_free(&result); intern->rescode = MEMC_RES_PAYLOAD_FAILURE; RETURN_FALSE; } array_init(return_value); - add_assoc_stringl_ex(return_value, ZEND_STRL("key"), (char *)res_key, res_key_len); - add_assoc_zval_ex(return_value, ZEND_STRL("value"), &value); - if (cas != 0) { - /* XXX: also check against ULLONG_MAX or memc_behavior */ - add_assoc_double_ex(return_value, ZEND_STRL("cas"), (double)cas); - } - if (MEMC_VAL_GET_USER_FLAGS(flags) != 0) { - add_assoc_long_ex(return_value, ZEND_STRL("flags"), MEMC_VAL_GET_USER_FLAGS(flags)); - } + + flags = memcached_result_flags(&result); + res_key = memcached_result_key_value(&result); + res_key_len = memcached_result_key_length(&result); + cas = memcached_result_cas(&result); + + add_assoc_stringl_ex(return_value, ZEND_STRL("key"), (char *) res_key, res_key_len); + add_assoc_zval_ex(return_value, ZEND_STRL("value"), &value); + + s_uint64_to_zval (&zv_cas, cas); + add_assoc_zval_ex(return_value, ZEND_STRL("cas"), &zv_cas); + add_assoc_long_ex(return_value, ZEND_STRL("flags"), MEMC_VAL_GET_USER_FLAGS(flags)); memcached_result_free(&result); } @@ -1193,9 +1204,9 @@ PHP_METHOD(Memcached, fetchAll) size_t res_key_len = 0; const char *payload = NULL; size_t payload_len = 0; - zval value, entry; uint32_t flags; uint64_t cas = 0; + zval value, entry, zv_cas; memcached_result_st result; memcached_return status = MEMCACHED_SUCCESS; MEMC_METHOD_INIT_VARS; @@ -1211,30 +1222,27 @@ PHP_METHOD(Memcached, fetchAll) memcached_result_create(intern->memc, &result); while ((memcached_fetch_result(intern->memc, &result, &status)) != NULL) { - payload = memcached_result_value(&result); - payload_len = memcached_result_length(&result); - flags = memcached_result_flags(&result); - res_key = memcached_result_key_value(&result); - res_key_len = memcached_result_key_length(&result); - cas = memcached_result_cas(&result); - if (!s_memcached_result_to_zval(&result, &value)) { + if (!s_memcached_result_to_zval(intern->memc, &result, &value)) { memcached_result_free(&result); zval_dtor(return_value); intern->rescode = MEMC_RES_PAYLOAD_FAILURE; RETURN_FALSE; } + flags = memcached_result_flags(&result); + res_key = memcached_result_key_value(&result); + res_key_len = memcached_result_key_length(&result); + cas = memcached_result_cas(&result); + array_init(&entry); add_assoc_stringl_ex(&entry, ZEND_STRL("key"), (char *)res_key, res_key_len); - add_assoc_zval_ex(&entry, ZEND_STRL("value"), &value); - if (cas != 0) { - /* XXX: also check against ULLONG_MAX or memc_behavior */ - add_assoc_double_ex(&entry, ZEND_STRL("cas"), (double)cas); - } - if (MEMC_VAL_GET_USER_FLAGS(flags) != 0) { - add_assoc_long_ex(&entry, ZEND_STRL("flags"), MEMC_VAL_GET_USER_FLAGS(flags)); - } + add_assoc_zval_ex(&entry, ZEND_STRL("value"), &value); + + s_uint64_to_zval (&zv_cas, cas); + add_assoc_zval_ex(&entry, ZEND_STRL("cas"), &zv_cas); + add_assoc_long_ex(&entry, ZEND_STRL("flags"), MEMC_VAL_GET_USER_FLAGS(flags)); + add_next_index_zval(return_value, &entry); } @@ -2825,8 +2833,7 @@ static PHP_METHOD(Memcached, setSaslAuthData) return; } - if (!MEMC_G(sasl_enabled)) { - php_error_docref(NULL, E_WARNING, "SASL support (memcached.use_sasl) isn't enabled in php.ini"); + if (!php_memc_init_sasl_if_needed()) { RETURN_FALSE; } @@ -3363,7 +3370,7 @@ zend_string *s_decompress_value (const char *payload, size_t payload_len, uint32 } static -zend_bool s_unserialize_value (int val_type, zend_string *payload, zval *return_value) +zend_bool s_unserialize_value (memcached_st *memc, int val_type, zend_string *payload, zval *return_value) { switch (val_type) { case MEMC_VAL_IS_SERIALIZED: @@ -3402,7 +3409,10 @@ zend_bool s_unserialize_value (int val_type, zend_string *payload, zval *return_ case MEMC_VAL_IS_JSON: #ifdef HAVE_JSON_API - php_json_decode(return_value, payload->val, payload->len, (serializer == SERIALIZER_JSON_ARRAY), PHP_JSON_PARSER_DEFAULT_DEPTH); + { + php_memc_user_data_t *memc_user_data = memcached_get_user_data(memc); + php_json_decode(return_value, payload->val, payload->len, (memc_user_data->serializer == SERIALIZER_JSON_ARRAY), PHP_JSON_PARSER_DEFAULT_DEPTH); + } #else ZVAL_FALSE(return_value); php_error_docref(NULL, E_WARNING, "could not unserialize value, no json support"); @@ -3424,7 +3434,7 @@ zend_bool s_unserialize_value (int val_type, zend_string *payload, zval *return_ } static -zend_bool s_memcached_result_to_zval(memcached_result_st *result, zval *return_value) +zend_bool s_memcached_result_to_zval(memcached_st *memc, memcached_result_st *result, zval *return_value) { zend_string *data; const char *payload; @@ -3485,7 +3495,7 @@ zend_bool s_memcached_result_to_zval(memcached_result_st *result, zval *return_v case MEMC_VAL_IS_IGBINARY: case MEMC_VAL_IS_JSON: case MEMC_VAL_IS_MSGPACK: - retval = s_unserialize_value (MEMC_VAL_GET_TYPE(flags), data, return_value); + retval = s_unserialize_value (memc, MEMC_VAL_GET_TYPE(flags), data, return_value); break; default: @@ -3648,7 +3658,7 @@ int s_invoke_result_callback(zval *zmemc_obj, zend_fcall_info *fci, zend_fcall_i intern = Z_MEMC_OBJ_P(zmemc_obj); - if (!s_memcached_result_to_zval(result, &value)) { + if (!s_memcached_result_to_zval(intern->memc, result, &value)) { intern->rescode = MEMC_RES_PAYLOAD_FAILURE; return -1; } @@ -4159,37 +4169,35 @@ PHP_GINIT_FUNCTION(php_memcached) { #ifdef HAVE_MEMCACHED_SESSION - php_memcached_globals->session_ini.lock_enabled = 0; - php_memcached_globals->session_ini.lock_wait_max = 2000; - php_memcached_globals->session_ini.lock_wait_min = 1000; - php_memcached_globals->session_ini.lock_retries = 5; - php_memcached_globals->session_ini.lock_expiration = 30; - php_memcached_globals->session_ini.compression_enabled = 1; - php_memcached_globals->session_ini.binary_protocol_enabled = 1; - php_memcached_globals->session_ini.consistent_hash_enabled = 1; - php_memcached_globals->session_ini.number_of_replicas = 0; - php_memcached_globals->session_ini.server_failure_limit = 1; - php_memcached_globals->session_ini.randomize_replica_read_enabled = 1; - php_memcached_globals->session_ini.remove_failed_servers_enabled = 1; - php_memcached_globals->session_ini.connect_timeout = 1000; - php_memcached_globals->session_ini.prefix = NULL; - php_memcached_globals->session_ini.persistent_enabled = 0; - php_memcached_globals->session_ini.sasl_username = NULL; - php_memcached_globals->session_ini.sasl_password = NULL; + php_memcached_globals->session.lock_enabled = 0; + php_memcached_globals->session.lock_wait_max = 2000; + php_memcached_globals->session.lock_wait_min = 1000; + php_memcached_globals->session.lock_retries = 5; + php_memcached_globals->session.lock_expiration = 30; + php_memcached_globals->session.compression_enabled = 1; + php_memcached_globals->session.binary_protocol_enabled = 1; + php_memcached_globals->session.consistent_hash_enabled = 1; + php_memcached_globals->session.number_of_replicas = 0; + php_memcached_globals->session.server_failure_limit = 1; + php_memcached_globals->session.randomize_replica_read_enabled = 1; + php_memcached_globals->session.remove_failed_servers_enabled = 1; + php_memcached_globals->session.connect_timeout = 1000; + php_memcached_globals->session.prefix = NULL; + php_memcached_globals->session.persistent_enabled = 0; + php_memcached_globals->session.sasl_username = NULL; + php_memcached_globals->session.sasl_password = NULL; - php_memcached_globals->no_effect = 0; - -#endif - php_memcached_globals->memc_ini.serializer_name = NULL; - php_memcached_globals->memc_ini.serializer = SERIALIZER_DEFAULT; - php_memcached_globals->memc_ini.compression_type = NULL; - php_memcached_globals->memc_ini.compression_threshold = 2000; - php_memcached_globals->memc_ini.compression_type_real = COMPRESSION_TYPE_FASTLZ; - php_memcached_globals->memc_ini.compression_factor = 1.30; - php_memcached_globals->memc_ini.store_retry_count = 2; -#if HAVE_MEMCACHED_SASL - php_memcached_globals->memc_ini.sasl_enabled = 0; #endif + php_memcached_globals->memc.serializer_name = NULL; + php_memcached_globals->memc.serializer = SERIALIZER_DEFAULT; + php_memcached_globals->memc.compression_type = NULL; + php_memcached_globals->memc.compression_threshold = 2000; + php_memcached_globals->memc.compression_type_real = COMPRESSION_TYPE_FASTLZ; + php_memcached_globals->memc.compression_factor = 1.30; + php_memcached_globals->memc.store_retry_count = 2; + + php_memcached_globals->memc.sasl_initialised = 0; + php_memcached_globals->no_effect = 0; } zend_module_entry memcached_module_entry = { @@ -4385,11 +4393,11 @@ static void php_memc_register_constants(INIT_FUNC_ARGS) /* * Serializer types. */ - REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_PHP, SERIALIZER_PHP); - REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_IGBINARY, SERIALIZER_IGBINARY); - REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_JSON, SERIALIZER_JSON); + REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_PHP, SERIALIZER_PHP); + REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_IGBINARY, SERIALIZER_IGBINARY); + REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_JSON, SERIALIZER_JSON); REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_JSON_ARRAY, SERIALIZER_JSON_ARRAY); - REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_MSGPACK, SERIALIZER_MSGPACK); + REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_MSGPACK, SERIALIZER_MSGPACK); /* * Compression types @@ -4487,15 +4495,6 @@ PHP_MINIT_FUNCTION(memcached) #ifdef HAVE_MEMCACHED_SESSION php_memc_session_minit(module_number); #endif - -#if HAVE_MEMCACHED_SASL - if (MEMC_G(sasl_enabled)) { - if (sasl_client_init(NULL) != SASL_OK) { - php_error_docref(NULL, E_ERROR, "Failed to initialize SASL library"); - return FAILURE; - } - } -#endif return SUCCESS; } /* }}} */ @@ -4504,7 +4503,7 @@ PHP_MINIT_FUNCTION(memcached) PHP_MSHUTDOWN_FUNCTION(memcached) { #if HAVE_MEMCACHED_SASL - if (MEMC_G(sasl_enabled)) { + if (MEMC_G(sasl_initialised)) { sasl_done(); } #endif diff --git a/php_memcached_private.h b/php_memcached_private.h index 4a4dc4fe..c6c0b77c 100644 --- a/php_memcached_private.h +++ b/php_memcached_private.h @@ -155,8 +155,7 @@ ZEND_BEGIN_MODULE_GLOBALS(php_memcached) char *sasl_username; char *sasl_password; - } session_ini; - + } session; #endif struct { @@ -166,15 +165,14 @@ ZEND_BEGIN_MODULE_GLOBALS(php_memcached) double compression_factor; zend_long store_retry_count; -#if HAVE_MEMCACHED_SASL - zend_bool sasl_enabled; -#endif - /* Converted values*/ enum memcached_serializer serializer; zend_long compression_type_real; - } memc_ini; + /* Whether we have initialised sasl for this process */ + zend_bool sasl_initialised; + + } memc; /* For deprecated values */ zend_long no_effect; @@ -194,10 +192,12 @@ PHP_MINIT_FUNCTION(memcached); PHP_MSHUTDOWN_FUNCTION(memcached); PHP_MINFO_FUNCTION(memcached); -char *php_memc_printable_func (zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TSRMLS_DC); +char *php_memc_printable_func (zend_fcall_info *fci, zend_fcall_info_cache *fci_cache); memcached_return php_memcached_exist (memcached_st *memc, zend_string *key); +zend_bool php_memc_init_sasl_if_needed(); + #endif /* PHP_MEMCACHED_PRIVATE_H */ /* diff --git a/php_memcached_session.c b/php_memcached_session.c index 34bfc77c..bfb34e99 100644 --- a/php_memcached_session.c +++ b/php_memcached_session.c @@ -45,9 +45,9 @@ typedef struct { #endif #ifdef ZTS -#define MEMC_SESS_INI(v) TSRMG(php_memcached_globals_id, zend_php_memcached_globals *, session_ini.v) +#define MEMC_SESS_INI(v) TSRMG(php_memcached_globals_id, zend_php_memcached_globals *, session.v) #else -#define MEMC_SESS_INI(v) (php_memcached_globals.session_ini.v) +#define MEMC_SESS_INI(v) (php_memcached_globals.session.v) #endif #define MEMC_SESS_STR_INI(vv) ((MEMC_SESS_INI(vv) && *MEMC_SESS_INI(vv)) ? MEMC_SESS_INI(vv) : NULL) @@ -138,7 +138,7 @@ zend_bool s_lock_session(memcached_st *memc, zend_string *sid) switch (rc) { case MEMCACHED_SUCCESS: - user_data->lock_key = zend_string_init(lock_key, lock_key_len, user_data->is_persistent); + user_data->lock_key = zend_string_init(lock_key, lock_key_len, user_data->is_persistent); user_data->is_locked = 1; break; @@ -215,10 +215,13 @@ zend_bool s_configure_from_ini_values(memcached_st *memc, zend_bool silent) memcached_callback_set(memc, MEMCACHED_CALLBACK_NAMESPACE, MEMC_SESS_STR_INI(prefix)); } -#ifdef HAVE_MEMCACHED_SASL if (MEMC_SESS_STR_INI(sasl_username) && MEMC_SESS_STR_INI(sasl_password)) { php_memcached_user_data *user_data; + if (!php_memc_init_sasl_if_needed()) { + return 0; + } + check_set_behavior(MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1); if (memcached_set_sasl_auth_data(memc, MEMC_SESS_STR_INI(sasl_username), MEMC_SESS_STR_INI(sasl_password)) == MEMCACHED_FAILURE) { @@ -228,7 +231,6 @@ zend_bool s_configure_from_ini_values(memcached_st *memc, zend_bool silent) user_data = memcached_get_user_data(memc); user_data->has_sasl_data = 1; } -#endif #undef safe_set_behavior @@ -297,7 +299,6 @@ memcached_st *s_init_mod_data (const memcached_server_list_st servers, zend_bool memcached_set_user_data(memc, user_data); memcached_server_push (memc, servers); - memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_VERIFY_KEY, 1); return memc; } @@ -307,6 +308,7 @@ PS_OPEN_FUNC(memcached) memcached_st *memc = NULL; char *plist_key = NULL; size_t plist_key_len = 0; + memcached_server_list_st servers; // First parse servers @@ -348,6 +350,7 @@ PS_OPEN_FUNC(memcached) if (plist_key) { efree(plist_key); } + s_destroy_mod_data(memc); PS_SET_MOD_DATA(NULL); return FAILURE; } @@ -503,21 +506,6 @@ PS_CREATE_SID_FUNC(memcached) sid = NULL; } } - - if (sid) { - if (sid->len + (sizeof ("lock.") - 1) > (MEMCACHED_MAX_KEY - 1)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session id is too long to be stored in memcached"); - zend_string_release (sid); - return NULL; - } - if (MEMC_SESS_STR_INI(prefix)) { - if (strlen (MEMC_SESS_STR_INI(prefix)) + sid->len + (sizeof ("lock.") - 1) > (MEMCACHED_MAX_KEY - 1)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session id with prefix is too long to be stored in memcached"); - zend_string_release (sid); - return NULL; - } - } - } return sid; } diff --git a/tests/types_json_multi.phpt b/tests/types_json_multi.phpt index 5535abb8..6a085039 100644 --- a/tests/types_json_multi.phpt +++ b/tests/types_json_multi.phpt @@ -3,7 +3,7 @@ Memcached multi store & multi fetch type and value correctness using JSON serial --SKIPIF-- --FILE-- Date: Mon, 1 Feb 2016 01:12:26 +0000 Subject: [PATCH 058/104] Fix serializers --- .travis/travis.sh | 18 +++++++++--------- php_memcached.c | 11 +++++++++-- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/.travis/travis.sh b/.travis/travis.sh index 131e38bf..1eab43fb 100755 --- a/.travis/travis.sh +++ b/.travis/travis.sh @@ -67,8 +67,8 @@ function install_libmemcached() { } function install_igbinary() { - git clone https://github.com/igbinary/igbinary.git - pushd igbinary + git clone https://github.com/igbinary/igbinary7.git + pushd igbinary7 phpize ./configure make @@ -79,7 +79,7 @@ function install_igbinary() { function install_msgpack() { git clone https://github.com/msgpack/msgpack-php.git pushd msgpack-php - git checkout php7 + git checkout php7 phpize ./configure make @@ -152,9 +152,9 @@ function build_php_memcached() { sasl_flag="--enable-memcached-sasl" fi - # ./configure --with-libmemcached-dir="$LIBMEMCACHED_PREFIX" $protocol_flag $sasl_flag --enable-memcached-json --enable-memcached-msgpack --enable-memcached-igbinary - ./configure --with-libmemcached-dir="$LIBMEMCACHED_PREFIX" $protocol_flag $sasl_flag - make + # ./configure --with-libmemcached-dir="$LIBMEMCACHED_PREFIX" $protocol_flag $sasl_flag + ./configure --with-libmemcached-dir="$LIBMEMCACHED_PREFIX" $protocol_flag $sasl_flag --enable-memcached-json --enable-memcached-msgpack --enable-memcached-igbinary + make make install popd } @@ -184,7 +184,7 @@ function run_memcached_tests() { rm ./tests/expire.phpt # Run normal tests - php run-tests.php --show-diff -d extension=memcached.so -n ./tests/*.phpt + php run-tests.php --show-diff -d extension=modules/memcached.so -d extension=msgpack.so -d extension=igbinary.so -n ./tests/*.phpt retval=$? popd return $retval; @@ -236,10 +236,10 @@ case $ACTION in install_libmemcached # Install igbinary extension - # install_igbinary + install_igbinary # install msgpack - # install_msgpack + install_msgpack install_memcached run_memcached diff --git a/php_memcached.c b/php_memcached.c index cf8116a8..a8d9605b 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -3187,11 +3187,18 @@ zend_bool s_serialize_value (enum memcached_serializer serializer, zval *value, */ #ifdef HAVE_MEMCACHED_IGBINARY case SERIALIZER_IGBINARY: - if (igbinary_serialize((uint8_t **) &(buf->s), &buf->s->len, value) != 0) { + { + uint8_t *buffer; + size_t buffer_len; + + if (igbinary_serialize(&buffer, &buffer_len, value) != 0) { php_error_docref(NULL, E_WARNING, "could not serialize value with igbinary"); return 0; } + smart_str_appendl (buf, buffer, buffer_len); + efree(buffer); MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_IGBINARY); + } break; #endif @@ -3395,7 +3402,7 @@ zend_bool s_unserialize_value (memcached_st *memc, int val_type, zend_string *pa case MEMC_VAL_IS_IGBINARY: #ifdef HAVE_MEMCACHED_IGBINARY - if (igbinary_unserialize((uint8_t *) payload->val, payload->len, &value)) { + if (igbinary_unserialize((uint8_t *) payload->val, payload->len, return_value)) { ZVAL_FALSE(return_value); php_error_docref(NULL, E_WARNING, "could not unserialize value with igbinary"); return 0; From cf4d0ead4fcccbfd86cfd2ff1e0278d9c463f470 Mon Sep 17 00:00:00 2001 From: Mikko Date: Mon, 1 Feb 2016 01:34:03 +0000 Subject: [PATCH 059/104] Update package.xml for release along with memcached.ini --- memcached.ini | 31 +++++++++++++------------------ package.xml | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 18 deletions(-) diff --git a/memcached.ini b/memcached.ini index 1996eb27..1aa9f266 100644 --- a/memcached.ini +++ b/memcached.ini @@ -4,19 +4,19 @@ ; the default is On memcached.sess_locking = On -; Session spin lock retry wait time in microseconds. -; Be carefull when setting this value. -; Valid values are integers, where 0 is interpreted as -; the default value. Negative values result in a reduces -; locking to a try lock. -; the default is 150000 -memcached.sess_lock_wait = 150000 - -; The maximum time, in seconds, to wait for a session lock -; before timing out. -; Setting to 0 results in default behavior, which is to -; use max_execution_time. -memcached.sess_lock_max_wait = 0; +; !! DEPRECATED AND REMOVED in 3.x !! +; memcached.sess_lock_wait = 150000 + +; !! DEPRECATED AND REMOVED in 3.x !! +; memcached.sess_lock_max_wait = 0; + +; The minimum time, in milliseconds, to wait between session lock attempts. +; This value is double on each lock retry until memcached.sess_lock_wait_max +; is reached +memcached.sess_lock_wait_min = 0; + +; The maximum time, in milliseconds, to wait between session lock attempts. +memcached.sess_lock_wait_max = 0; ; The time, in seconds, before a lock should release itself. ; Setting to 0 results in the default behaviour, which is to @@ -105,11 +105,6 @@ memcached.compression_threshold = 2000 ; The default is igbinary if available, then msgpack if available, then php otherwise. memcached.serializer = "igbinary" -; Use SASL authentication for connections -; valid values: On, Off -; the default is Off -memcached.use_sasl = Off - ; The amount of retries for failed store commands. ; This mechanism allows transparent fail-over to secondary servers when ; set/increment/decrement/setMulti operations fail on the desired server in a multi-server diff --git a/package.xml b/package.xml index 6c162a14..39175882 100644 --- a/package.xml +++ b/package.xml @@ -159,6 +159,42 @@ http://pear.php.net/dtd/package-2.0.xsd"> + + + beta + beta + + + 3.0.0 + 3.0.0 + + 2016-02-01 + +PHP7 release of memcached extension. Note that support for libmemcached 0.x series has been discontinued +and the earliest actively tested version is 1.0.2. It is highly recommended to use version 1.0.18 of +libmemcached. + +API + * set/get commands do not take cas or user flags parameters + * get and getMulti commands take Memcached::GET_EXTENDED flag to retrieve user flags and cas tokens + * Fixes getStats command to return all stats from all servers + * Fixes allKeys command behaviour + * Fixes error where cache callback for get command was not setting expiration time properly + * Added server type to server list + * Remove use_sasl ini-variable and initialise sasl as needed + +Session handler + * Session lock algorithm updated (new ini-values memcached.sess_lock_wait_min, memcached.sess_lock_wait_max and memcached.sess_lock_retries) + * Session extension uses PHP allocators (still some work to do on the rest of the extension) + * Ini-values take effect during session_start or session_regenerate_id + * Fixes crash with session_regenerate_id (work-around for PHP bug) + +Tests + * Fix several broken tests + + + + stablestable 2.2.02.2.0 From a93ff86f7c94b811a8bf5c69f8b576c2d08acc29 Mon Sep 17 00:00:00 2001 From: Mikko Date: Mon, 1 Feb 2016 01:37:36 +0000 Subject: [PATCH 060/104] More package.xml / version updates --- package.xml | 12 ++++++------ php_memcached.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package.xml b/package.xml index 39175882..29c617e7 100644 --- a/package.xml +++ b/package.xml @@ -21,14 +21,14 @@ http://pear.php.net/dtd/package-2.0.xsd"> mkoppanen@php.net yes - 2014-04-01 + 2016-02-01 - 2.2.0 - 2.2.0 + 3.0.0b1 + 3.0.0 - stable - stable + beta + beta PHP @@ -165,7 +165,7 @@ http://pear.php.net/dtd/package-2.0.xsd"> beta - 3.0.0 + 3.0.0b1 3.0.0 2016-02-01 diff --git a/php_memcached.h b/php_memcached.h index b96ef37a..9e466cb4 100644 --- a/php_memcached.h +++ b/php_memcached.h @@ -27,7 +27,7 @@ # include "config.h" #endif -#define PHP_MEMCACHED_VERSION "2.2.0" +#define PHP_MEMCACHED_VERSION "3.0.0b1" #if defined(PHP_WIN32) && defined(MEMCACHED_EXPORTS) #define PHP_MEMCACHED_API __declspec(dllexport) From 938f6bcf68ff5cf07884cbf4963336c3e8fe7f2f Mon Sep 17 00:00:00 2001 From: Mikko Date: Mon, 1 Feb 2016 01:40:17 +0000 Subject: [PATCH 061/104] Update right place in package.xml --- package.xml | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/package.xml b/package.xml index 29c617e7..d2088a12 100644 --- a/package.xml +++ b/package.xml @@ -32,7 +32,27 @@ http://pear.php.net/dtd/package-2.0.xsd"> PHP -- Added the OPT_SERVER_TIMEOUT_LIMIT behaviour +PHP7 release of memcached extension. Note that support for libmemcached 0.x series has been discontinued +and the earliest actively tested version is 1.0.2. It is highly recommended to use version 1.0.18 of +libmemcached. + +API + * set/get commands do not take cas or user flags parameters + * get and getMulti commands take Memcached::GET_EXTENDED flag to retrieve user flags and cas tokens + * Fixes getStats command to return all stats from all servers + * Fixes allKeys command behaviour + * Fixes error where cache callback for get command was not setting expiration time properly + * Added server type to server list + * Remove use_sasl ini-variable and initialise sasl as needed + +Session handler + * Session lock algorithm updated (new ini-values memcached.sess_lock_wait_min, memcached.sess_lock_wait_max and memcached.sess_lock_retries) + * Session extension uses PHP allocators (still some work to do on the rest of the extension) + * Ini-values take effect during session_start or session_regenerate_id + * Fixes crash with session_regenerate_id (work-around for PHP bug) + +Tests + * Fix several broken tests @@ -191,10 +211,8 @@ Session handler Tests * Fix several broken tests - - stablestable 2.2.02.2.0 From a930b41fa138a55b976c55e21157e57b09355343 Mon Sep 17 00:00:00 2001 From: Mikko Date: Sat, 6 Feb 2016 05:07:52 +0000 Subject: [PATCH 062/104] Fixes memory errors, broken code, bugs etc --- package.xml | 1 + php_libmemcached_compat.c | 40 +- php_libmemcached_compat.h | 2 +- php_memcached.c | 4235 +++++++++++++++---------------- php_memcached_private.h | 29 +- tests/getdelayed.phpt | 37 +- tests/incrdecr_invalid_key.phpt | 1 + 7 files changed, 2128 insertions(+), 2217 deletions(-) diff --git a/package.xml b/package.xml index d2088a12..9d3be440 100644 --- a/package.xml +++ b/package.xml @@ -202,6 +202,7 @@ API * Fixes error where cache callback for get command was not setting expiration time properly * Added server type to server list * Remove use_sasl ini-variable and initialise sasl as needed + * CAS tokens are returned as integers and in case of too large values they overflow to strings Session handler * Session lock algorithm updated (new ini-values memcached.sess_lock_wait_min, memcached.sess_lock_wait_max and memcached.sess_lock_retries) diff --git a/php_libmemcached_compat.c b/php_libmemcached_compat.c index f49b162b..bd35d8fe 100644 --- a/php_libmemcached_compat.c +++ b/php_libmemcached_compat.c @@ -18,36 +18,20 @@ #include "php_memcached_private.h" #include "php_libmemcached_compat.h" -memcached_st *php_memc_create_str (const char *str, size_t str_len) +memcached_return php_memcached_exist (memcached_st *memc, zend_string *key) { -#ifdef HAVE_LIBMEMCACHED_MEMCACHED - return memcached (str, str_len); +#ifdef HAVE_MEMCACHED_EXIST + return memcached_exist (memc, key->val, key->len); #else - memcached_return rc; - memcached_st *memc; - memcached_server_st *servers; - - memc = memcached_create(NULL); - - if (!memc) { - return NULL; - } - - servers = memcached_servers_parse (str); - - if (!servers) { - memcached_free (memc); - return NULL; + memcached_return rc = MEMCACHED_SUCCESS; + uint32_t flags = 0; + size_t value_length = 0; + char *value = NULL; + + value = memcached_get (memc, key->val, key->len, &value_length, &flags, &rc); + if (value) { + free (value); } - - rc = memcached_server_push (memc, servers); - memcached_server_free (servers); - - if (rc != MEMCACHED_SUCCESS) { - memcached_free (memc); - return NULL; - } - return memc; + return rc; #endif } - diff --git a/php_libmemcached_compat.h b/php_libmemcached_compat.h index ae400d9c..e740d310 100644 --- a/php_libmemcached_compat.h +++ b/php_libmemcached_compat.h @@ -20,7 +20,7 @@ /* this is the version(s) we support */ #include -memcached_st *php_memc_create_str (const char *str, size_t str_len); +memcached_return php_memcached_exist (memcached_st *memc, zend_string *key); #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x00052000 # define MEMCACHED_SERVER_TEMPORARILY_DISABLED (1024 << 2) diff --git a/php_memcached.c b/php_memcached.c index a8d9605b..c01b7f94 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -27,6 +27,9 @@ #include "php_memcached_server.h" #include "g_fmt.h" +#include +#include + #ifdef HAVE_MEMCACHED_SESSION # include "php_memcached_session.h" #endif @@ -55,8 +58,14 @@ #define MEMC_G(v) (php_memcached_globals.memc.v) #endif -#include + static + int le_memc; +static +int php_memc_list_entry(void) +{ + return le_memc; +} /**************************************** Custom options @@ -113,30 +122,34 @@ /**************************************** "get" operation flags ****************************************/ -#define MEMC_GET_PRESERVE_ORDER (1<<0) -#define MEMC_GET_EXTENDED (2<<0) +#define MEMC_GET_PRESERVE_ORDER 1 +#define MEMC_GET_EXTENDED 2 /**************************************** Helper macros ****************************************/ - - #define RETURN_FROM_GET RETURN_FALSE /**************************************** Structures and definitions ****************************************/ -enum memcached_compression_type { - COMPRESSION_TYPE_ZLIB = 1, - COMPRESSION_TYPE_FASTLZ = 2, -}; + +typedef enum { + MEMC_OP_SET, + MEMC_OP_TOUCH, + MEMC_OP_ADD, + MEMC_OP_REPLACE, + MEMC_OP_APPEND, + MEMC_OP_PREPEND +} php_memc_write_op; typedef struct { zend_bool is_persistent; - zend_bool compression; - enum memcached_serializer serializer; - enum memcached_compression_type compression_type; + zend_bool compression_enabled; + + zend_long serializer; + zend_long compression_type; zend_long store_retry_count; zend_long set_udf_flags; @@ -144,10 +157,8 @@ typedef struct { #if HAVE_MEMCACHED_SASL zend_bool has_sasl_data; #endif - } php_memc_user_data_t; - typedef struct { memcached_st *memc; zend_bool is_pristine; @@ -156,6 +167,22 @@ typedef struct { zend_object zo; } php_memc_object_t; +typedef struct { + size_t num_valid_keys; + + const char **mkeys; + size_t *mkeys_len; + + zend_string **strings; + +} php_memc_keys_t; + +typedef struct { + zval *object; + zend_fcall_info fci; + zend_fcall_info_cache fcc; +} php_memc_result_callback_ctx_t; + static inline php_memc_object_t *php_memc_fetch_object(zend_object *obj) { return (php_memc_object_t *)((char *)obj - XtOffsetOf(php_memc_object_t, zo)); } @@ -184,15 +211,6 @@ typedef struct { #endif -enum { - MEMC_OP_SET, - MEMC_OP_TOUCH, - MEMC_OP_ADD, - MEMC_OP_REPLACE, - MEMC_OP_APPEND, - MEMC_OP_PREPEND -}; - static zend_class_entry *memcached_ce = NULL; static zend_class_entry *memcached_exception_ce = NULL; @@ -217,11 +235,11 @@ ZEND_GET_MODULE(memcached) static PHP_INI_MH(OnUpdateCompressionType) { if (!new_value) { - MEMC_G(compression_type_real) = COMPRESSION_TYPE_FASTLZ; + MEMC_G(compression_type) = COMPRESSION_TYPE_FASTLZ; } else if (!strcmp(new_value->val, "fastlz")) { - MEMC_G(compression_type_real) = COMPRESSION_TYPE_FASTLZ; + MEMC_G(compression_type) = COMPRESSION_TYPE_FASTLZ; } else if (!strcmp(new_value->val, "zlib")) { - MEMC_G(compression_type_real) = COMPRESSION_TYPE_ZLIB; + MEMC_G(compression_type) = COMPRESSION_TYPE_ZLIB; } else { return FAILURE; } @@ -231,22 +249,22 @@ static PHP_INI_MH(OnUpdateCompressionType) static PHP_INI_MH(OnUpdateSerializer) { if (!new_value) { - MEMC_G(serializer) = SERIALIZER_DEFAULT; + MEMC_G(serializer_type) = SERIALIZER_DEFAULT; } else if (!strcmp(new_value->val, "php")) { - MEMC_G(serializer) = SERIALIZER_PHP; + MEMC_G(serializer_type) = SERIALIZER_PHP; #ifdef HAVE_MEMCACHED_IGBINARY } else if (!strcmp(new_value->val, "igbinary")) { - MEMC_G(serializer) = SERIALIZER_IGBINARY; + MEMC_G(serializer_type) = SERIALIZER_IGBINARY; #endif // IGBINARY #ifdef HAVE_JSON_API } else if (!strcmp(new_value->val, "json")) { - MEMC_G(serializer) = SERIALIZER_JSON; + MEMC_G(serializer_type) = SERIALIZER_JSON; } else if (!strcmp(new_value->val, "json_array")) { - MEMC_G(serializer) = SERIALIZER_JSON_ARRAY; + MEMC_G(serializer_type) = SERIALIZER_JSON_ARRAY; #endif // JSON #ifdef HAVE_MEMCACHED_MSGPACK } else if (!strcmp(new_value->val, "msgpack")) { - MEMC_G(serializer) = SERIALIZER_MSGPACK; + MEMC_G(serializer_type) = SERIALIZER_MSGPACK; #endif // msgpack } else { return FAILURE; @@ -300,7 +318,6 @@ PHP_INI_BEGIN() MEMC_SESSION_INI_ENTRY("lock_wait_max", "2000", OnUpdateLongGEZero, lock_wait_max) MEMC_SESSION_INI_ENTRY("lock_retries", "5", OnUpdateLong, lock_retries) MEMC_SESSION_INI_ENTRY("lock_expire", "0", OnUpdateLongGEZero, lock_expiration) - MEMC_SESSION_INI_ENTRY("compression", "1", OnUpdateBool, compression_enabled) MEMC_SESSION_INI_ENTRY("binary_protocol", "1", OnUpdateBool, binary_protocol_enabled) MEMC_SESSION_INI_ENTRY("consistent_hash", "1", OnUpdateBool, consistent_hash_enabled) MEMC_SESSION_INI_ENTRY("number_of_replicas", "0", OnUpdateLongGEZero, number_of_replicas) @@ -319,7 +336,7 @@ PHP_INI_BEGIN() #endif - MEMC_INI_ENTRY("compression_type", "fastlz", OnUpdateCompressionType, compression_type) + MEMC_INI_ENTRY("compression_type", "fastlz", OnUpdateCompressionType, compression_name) MEMC_INI_ENTRY("compression_factor", "1.3", OnUpdateReal, compression_factor) MEMC_INI_ENTRY("compression_threshold", "2000", OnUpdateLong, compression_threshold) MEMC_INI_ENTRY("serializer", SERIALIZER_DEFAULT_NAME, OnUpdateSerializer, serializer_name) @@ -333,8 +350,6 @@ PHP_INI_END() /**************************************** Forward declarations ****************************************/ -static int php_memc_handle_error(php_memc_object_t *intern, memcached_return status); - static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key); static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key); static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool by_key); @@ -345,10 +360,19 @@ static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ /* Invoke PHP functions */ static - memcached_return s_invoke_cache_callback(zval *zobject, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string *key, zval *value); + zend_bool s_invoke_cache_callback(zval *zobject, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string *key, zval *value); + +/* Iterate result sets */ +typedef zend_bool (*php_memc_result_apply_fn)(php_memc_object_t *intern, zend_string *key, zval *value, zval *cas, uint32_t flags, void *context); + +static +memcached_return php_memc_result_apply(php_memc_object_t *intern, php_memc_result_apply_fn result_apply_fn, void *context); static - int s_invoke_result_callback(zval *zmemc_obj, zend_fcall_info *fci, zend_fcall_info_cache *fcc, memcached_result_st *result); +zend_bool php_memc_mget_apply(php_memc_object_t *intern, zend_string *server_key, + php_memc_keys_t *keys, php_memc_result_apply_fn result_apply_fn, + zend_bool with_cas, void *context); + /* Callback functions for different server list iterations */ static @@ -357,8 +381,8 @@ static static memcached_return s_server_cursor_version_cb(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context); -/* Callback for dumping all keys to zval */ - +static + zend_bool s_memc_write_zval (php_memc_object_t *intern, php_memc_write_op op, zend_string *server_key, zend_string *key, zval *value, time_t expiration); static void php_memc_destroy(memcached_st *memc, php_memc_user_data_t *memc_user_data); @@ -367,11 +391,17 @@ static zend_bool s_memcached_result_to_zval(memcached_st *memc, memcached_result_st *result, zval *return_value); static - zend_string *s_zval_to_payload(zval *value, uint32_t *flags, enum memcached_serializer serializer, enum memcached_compression_type compression_type); + zend_string *s_zval_to_payload(php_memc_object_t *intern, zval *value, uint32_t *flags); + +static + void s_hash_to_keys(php_memc_keys_t *keys_out, HashTable *hash_in, zend_bool preserve_order, zval *return_value); + +static + void s_clear_keys(php_memc_keys_t *keys); /**************************************** - Method implementations + Exported helper functions ****************************************/ zend_bool php_memc_init_sasl_if_needed() @@ -391,27 +421,6 @@ zend_bool php_memc_init_sasl_if_needed() #endif } - - -memcached_return php_memcached_exist (memcached_st *memc, zend_string *key) -{ -#ifdef HAVE_MEMCACHED_EXIST - return memcached_exist (memc, key->val, key->len); -#else - memcached_return rc = MEMCACHED_SUCCESS; - uint32_t flags = 0; - size_t value_length = 0; - char *value = NULL; - - value = memcached_get (memc, key->val, key->len, &value_length, &flags, &rc); - if (value) { - free (value); - } - return rc; -#endif -} - - char *php_memc_printable_func (zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) { char *buffer = NULL; @@ -429,1646 +438,1558 @@ char *php_memc_printable_func (zend_fcall_info *fci, zend_fcall_info_cache *fci_ return buffer; } + +/**************************************** + Handling error codes +****************************************/ + static -zend_bool s_invoke_new_instance_cb(zval *object, zend_fcall_info *fci, zend_fcall_info_cache *fci_cache, zend_string *persistent_id) +zend_bool s_memcached_return_is_error(memcached_return status, zend_bool strict) { - zend_bool ret = 1; - zval retval, id; - - if (persistent_id) { - ZVAL_STR(&id, persistent_id); - } else { - ZVAL_NULL(&id); - } + zend_bool result = 0; - ZVAL_UNDEF(&retval); + switch (status) { + case MEMCACHED_SUCCESS: + case MEMCACHED_STORED: + case MEMCACHED_DELETED: + case MEMCACHED_STAT: + case MEMCACHED_END: + case MEMCACHED_BUFFERED: + result = 0; + break; - zend_fcall_info_argn(fci, 2, object, &id); - fci->retval = &retval; - fci->no_separation = 1; + case MEMCACHED_SOME_ERRORS: + result = strict; + break; - if (zend_call_function(fci, fci_cache) == FAILURE) { - char *buf = php_memc_printable_func (fci, fci_cache); - php_error_docref(NULL, E_WARNING, "Failed to invoke 'on_new' callback %s()", buf); - efree (buf); - ret = 0; + default: + result = 1; + break; } + return result; +} - if (Z_TYPE(retval) != IS_UNDEF) { - zval_ptr_dtor(&retval); - } +static +int s_memc_status_handle_result_code(php_memc_object_t *intern, memcached_return status) +{ + intern->rescode = status; + intern->memc_errno = 0; - if (EG(exception)) { - ret = 0; + if (s_memcached_return_is_error(status, 1)) { + intern->memc_errno = memcached_last_error_errno(intern->memc); + return FAILURE; } - - zend_fcall_info_args_clear(fci, 1); - return ret; + return SUCCESS; } static - int le_memc; +void s_memc_set_status(php_memc_object_t *intern, memcached_return status, int memc_errno) +{ + intern->rescode = status; + intern->memc_errno = memc_errno; +} static -int php_memc_list_entry(void) +zend_bool s_memc_status_has_error(php_memc_object_t *intern) { - return le_memc; + return s_memcached_return_is_error(intern->rescode, 1); } -/* {{{ Memcached::__construct([string persistent_id[, callback on_new[, string connection_str]]])) - Creates a Memcached object, optionally using persistent memcache connection */ -static PHP_METHOD(Memcached, __construct) +static +zend_bool s_memc_status_has_result_code(php_memc_object_t *intern, memcached_return status) { - php_memc_object_t *intern; - php_memc_user_data_t *memc_user_data; - - zend_string *persistent_id = NULL; - zend_string *conn_str = NULL; - zend_string *plist_key = NULL; - zend_fcall_info fci = {0}; - zend_fcall_info_cache fci_cache; + return intern->rescode == status; +} - zend_bool is_persistent = 0; +/**************************************** + Marshall cas tokens +****************************************/ - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!f!S", &persistent_id, &fci, &fci_cache, &conn_str) == FAILURE) { - return; +static +void s_uint64_to_zval (zval *target, uint64_t value) +{ + if (value >= ((uint64_t) LONG_MAX)) { + char *buffer; +#ifdef PRIu64 + spprintf (&buffer, 0, "%" PRIu64, value); +#else + /* Best effort */ + spprintf (&buffer, 0, "%llu", value); +#endif + ZVAL_STRING (target, buffer); + efree(buffer); + } + else { + ZVAL_LONG (target, (zend_long) value); } +} - intern = Z_MEMC_OBJ_P(getThis()); - intern->is_pristine = 1; +static +uint64_t s_zval_to_uint64 (zval *cas) +{ + switch (Z_TYPE_P (cas)) { + case IS_LONG: + return (uint64_t) zval_get_long (cas); + break; - if (persistent_id && persistent_id->len) { - zend_resource *le; + case IS_DOUBLE: + if (Z_DVAL_P (cas) < 0.0) + return 0; - plist_key = zend_string_alloc(sizeof("memcached:id=") + persistent_id->len - 1, 0); - snprintf(plist_key->val, plist_key->len + 1, "memcached:id=%s", persistent_id->val); + return (uint64_t) zval_get_double (cas); + break; - if ((le = zend_hash_find_ptr(&EG(persistent_list), plist_key)) != NULL) { - if (le->type == php_memc_list_entry()) { - intern->memc = le->ptr; - intern->is_pristine = 0; - zend_string_release (plist_key); - return; + case IS_STRING: + { + uint64_t val; + char *end; + + errno = 0; + val = (uint64_t) strtoull (Z_STRVAL_P (cas), &end, 0); + + if (*end || (errno == ERANGE && val == UINT64_MAX) || (errno != 0 && val == 0)) { + php_error_docref(NULL, E_ERROR, "Failed to unmarshall cas token"); + return 0; } + return val; } - is_persistent = 1; + break; } + return 0; +} - if (conn_str && conn_str->len > 0) { - intern->memc = memcached (conn_str->val, conn_str->len); - } - else { - intern->memc = memcached (NULL, 0); - } - if (!intern->memc) { - // TODO: handle allocation fail - } +/**************************************** + Iterate over memcached results and mget +****************************************/ - memc_user_data = pecalloc (1, sizeof(*memc_user_data), is_persistent); - memc_user_data->serializer = MEMC_G(serializer); - memc_user_data->compression_type = MEMC_G(compression_type_real); - memc_user_data->compression = 1; - memc_user_data->store_retry_count = MEMC_G(store_retry_count); - memc_user_data->set_udf_flags = -1; - memc_user_data->is_persistent = is_persistent; +static +memcached_return php_memc_result_apply(php_memc_object_t *intern, php_memc_result_apply_fn result_apply_fn, void *context) +{ + memcached_result_st result, *result_ptr; + memcached_return rc, status = MEMCACHED_SUCCESS; - memcached_set_user_data(intern->memc, memc_user_data); + memcached_result_create(intern->memc, &result); - if (fci.size) { - if (!s_invoke_new_instance_cb(getThis(), &fci, &fci_cache, persistent_id) || EG(exception)) { - /* error calling or exception thrown from callback */ - if (plist_key) { - zend_string_release(plist_key); - } - /* - Setting intern->memc null prevents object destruction from freeing the memcached_st - We free it manually here because it might be persistent and has not been - registered to persistent_list yet - */ - php_memc_destroy(intern->memc, memc_user_data); - intern->memc = NULL; - return; + do { + result_ptr = memcached_fetch_result(intern->memc, &result, &rc); + + if (s_memcached_return_is_error(rc, 0)) { + status = rc; } - } - if (plist_key) { - zend_resource le; + /* nothing returned */ + if (!result_ptr) { + break; + } + else { + zend_string *key; + zval zv_value, zv_cas; + zend_bool retval; - le.type = php_memc_list_entry(); - le.ptr = intern->memc; + uint64_t cas; + uint32_t flags; - GC_REFCOUNT(&le) = 1; + const char *res_key; + size_t res_key_len; + - /* plist_key is not a persistent allocated key, thus we use str_update here */ - if (zend_hash_str_update_mem(&EG(persistent_list), plist_key->val, plist_key->len, &le, sizeof(le)) == NULL) { - zend_string_release(plist_key); - php_error_docref(NULL, E_ERROR, "could not register persistent entry"); - /* not reached */ - } - zend_string_release(plist_key); - } + ZVAL_UNDEF(&zv_value); + if (!s_memcached_result_to_zval(intern->memc, &result, &zv_value)) { + if (Z_TYPE(zv_value) != IS_UNDEF) { + zval_ptr_dtor(&zv_value); + } + if (EG(exception)) { + status = MEMC_RES_PAYLOAD_FAILURE; + memcached_quit(intern->memc); + break; + } + status = MEMCACHED_SOME_ERRORS; + continue; + } + res_key = memcached_result_key_value(&result); + res_key_len = memcached_result_key_length(&result); + cas = memcached_result_cas(&result); + flags = memcached_result_flags(&result); -#if 0 - m_obj = pecalloc(1, sizeof(*m_obj), intern->is_persistent); - if (m_obj == NULL) { - if (plist_key) { - zend_string_release(plist_key); - } - php_error_docref(NULL, E_ERROR, "out of memory: cannot allocate handle"); - /* not reached */ - } + s_uint64_to_zval(&zv_cas, cas); - if (conn_str) { - intern->memc = php_memc_create_str(conn_str->val, conn_str->len); - if (!intern->memc) { - char error_buffer[1024]; - if (plist_key) { - zend_string_release(plist_key); - } -#ifdef HAVE_LIBMEMCACHED_CHECK_CONFIGURATION - if (libmemcached_check_configuration(conn_str->val, conn_str->len, error_buffer, sizeof(error_buffer)) != MEMCACHED_SUCCESS) { - php_error_docref(NULL, E_ERROR, "configuration error %s", error_buffer); - } else { - php_error_docref(NULL, E_ERROR, "could not allocate libmemcached structure"); - } -#else - php_error_docref(NULL, E_ERROR, "could not allocate libmemcached structure"); -#endif - /* not reached */ - } - } else { - intern->memc = memcached_create(NULL); - if (intern->memc == NULL) { - if (plist_key) { - zend_string_release(plist_key); + key = zend_string_init (res_key, res_key_len, 0); + retval = result_apply_fn(intern, key, &zv_value, &zv_cas, flags, context); + + zend_string_release (key); + zval_ptr_dtor(&zv_value); + zval_ptr_dtor(&zv_cas); + + /* Stop iterating on false */ + if (!retval) { + /* Make sure we clear our results */ + while (memcached_fetch_result(intern->memc, &result, &rc)) {} + break; } - php_error_docref(NULL, E_ERROR, "could not allocate libmemcached structure"); - /* not reached */ } - } + } while (result_ptr != NULL); + memcached_result_free(&result); + return status; +} +static +zend_bool php_memc_mget_apply(php_memc_object_t *intern, zend_string *server_key, php_memc_keys_t *keys, + php_memc_result_apply_fn result_apply_fn, zend_bool with_cas, void *context) +{ + memcached_return status; + memcached_result_st result; + int mget_status; + uint64_t orig_cas_flag = 0; - intern->obj = m_obj; - intern->is_pristine = 1; + // Reset status code + s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); - if (fci.size) { /* will be 0 when not available */ - if (!php_memcached_on_new_callback(object, &fci, &fci_cache, persistent_id) || EG(exception)) { - /* error calling or exception thrown from callback */ - if (plist_key) { - zend_string_release(plist_key); - } + if (!keys->num_valid_keys) { + intern->rescode = MEMCACHED_BAD_KEY_PROVIDED; + return 0; + } - intern->obj = NULL; - if (intern->is_persistent) { - php_memc_destroy(m_obj, intern->is_persistent); - } + if (with_cas) { + orig_cas_flag = memcached_behavior_get (intern->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS); - return; + if (!orig_cas_flag) { + memcached_behavior_set (intern->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1); } } - if (intern->is_persistent) { - zend_resource le; + if (server_key) { + status = memcached_mget_by_key(intern->memc, server_key->val, server_key->len, keys->mkeys, keys->mkeys_len, keys->num_valid_keys); + } else { + status = memcached_mget(intern->memc, keys->mkeys, keys->mkeys_len, keys->num_valid_keys); + } - le.type = php_memc_list_entry(); - le.ptr = m_obj; - GC_REFCOUNT(&le) = 1; - /* plist_key is not a persistent allocated key, thus we use str_update here */ - if (zend_hash_str_update_mem(&EG(persistent_list), plist_key->val, plist_key->len, &le, sizeof(le)) == NULL) { - if (plist_key) { - zend_string_release(plist_key); - } - php_error_docref(NULL, E_ERROR, "could not register persistent entry"); - /* not reached */ - } + /* Need to handle result code before restoring cas flags, would mess up errno */ + mget_status = s_memc_status_handle_result_code(intern, status); + + if (with_cas && !orig_cas_flag) { + memcached_behavior_set (intern->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, orig_cas_flag); } - if (plist_key) { - zend_string_release(plist_key); + /* Return on failure codes */ + if (mget_status == FAILURE) { + return 0; } -#endif -} -/* }}} */ -static -void s_uint64_to_zval (zval *target, uint64_t value) -{ - if (value >= LONG_MAX) { - char *buffer; -#ifdef PRIu64 - spprintf (&buffer, 0, "%" PRIu64, value); -#else - /* Best effort */ - spprintf (&buffer, 0, "%llu", value); -#endif - ZVAL_STRING (target, buffer); - efree(buffer); + if (!result_apply_fn) { + /* no callback, for example getDelayed */ + return 1; } - else { - ZVAL_LONG (target, (zend_long) value); + + status = php_memc_result_apply(intern, result_apply_fn, context); + + if (s_memc_status_handle_result_code(intern, status) == FAILURE) { + return 0; } + + return 1; } +/**************************************** + Invoke callbacks +****************************************/ + static -uint64_t s_zval_to_uint64 (zval *cas) +zend_bool s_invoke_new_instance_cb(zval *object, zend_fcall_info *fci, zend_fcall_info_cache *fci_cache, zend_string *persistent_id) { - switch (Z_TYPE_P (cas)) { - case IS_LONG: - return (uint64_t) zval_get_long (cas); - break; + zend_bool ret = 1; + zval retval, id; - case IS_DOUBLE: - if (Z_DVAL_P (cas) < 0.0) - return 0; + if (persistent_id) { + ZVAL_STR(&id, persistent_id); + } else { + ZVAL_NULL(&id); + } - return (uint64_t) zval_get_double (cas); - break; + ZVAL_UNDEF(&retval); - case IS_STRING: - { - uint64_t val; - char *end; + zend_fcall_info_argn(fci, 2, object, &id); + fci->retval = &retval; + fci->no_separation = 1; - errno = 0; - val = (uint64_t) strtoull (Z_STRVAL_P (cas), &end, 0); + if (zend_call_function(fci, fci_cache) == FAILURE) { + char *buf = php_memc_printable_func (fci, fci_cache); + php_error_docref(NULL, E_WARNING, "Failed to invoke 'on_new' callback %s()", buf); + efree (buf); + ret = 0; + } - if (*end || (errno == ERANGE && val == UINT64_MAX) || (errno != 0 && val == 0)) { - php_error_docref(NULL, E_ERROR, "Failed to unmarshall cas token"); - return 0; - } - return val; - } - break; + if (Z_TYPE(retval) != IS_UNDEF) { + zval_ptr_dtor(&retval); } - return 0; -} + if (EG(exception)) { + ret = 0; + } -typedef struct { + zend_fcall_info_args_clear(fci, 1); + return ret; +} - size_t num_valid_keys; +static +zend_bool s_invoke_cache_callback(zval *zobject, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string *key, zval *value) +{ + memcached_return rc; + zend_bool status = 0; - const char **mkeys; - size_t *mkeys_len; + zval params[4]; + zval retval; + zval zv_key, ref_val; + zval ref_expiration, zv_expiration; + php_memc_object_t *intern = Z_MEMC_OBJ_P(zobject); - zend_string **strings; + /* Prepare params */ + ZVAL_STR(&zv_key, key); -} php_memcached_keys; + ZVAL_NULL(&ref_val); + ZVAL_NULL(&zv_expiration); -static -void s_hash_to_keys(php_memcached_keys *keys_out, HashTable *hash_in, zend_bool preserve_order, zval *return_value) -{ - size_t idx = 0, alloc_count; - zval *zv; + ZVAL_NEW_REF(&ref_val, value); + ZVAL_NEW_REF(&ref_expiration, &zv_expiration); - keys_out->num_valid_keys = 0; + ZVAL_COPY(¶ms[0], zobject); + ZVAL_COPY(¶ms[1], &zv_key); + ZVAL_COPY_VALUE(¶ms[2], &ref_val); + ZVAL_COPY_VALUE(¶ms[3], &ref_expiration); - alloc_count = zend_hash_num_elements(hash_in); - if (!alloc_count) { - return; - } - keys_out->mkeys = ecalloc (alloc_count, sizeof (char *)); - keys_out->mkeys_len = ecalloc (alloc_count, sizeof (size_t)); - keys_out->strings = ecalloc (alloc_count, sizeof (zend_string *)); + fci->retval = &retval; + fci->params = params; + fci->param_count = 4; - ZEND_HASH_FOREACH_VAL(hash_in, zv) { - zend_string *key = zval_get_string(zv); + ZVAL_UNDEF(&retval); - if (preserve_order && return_value) { - add_assoc_null_ex(return_value, key->val, key->len); + if (zend_call_function(fci, fcc) == SUCCESS) { + if (zend_is_true(&retval)) { + time_t expiration = zval_get_long(Z_REFVAL(ref_expiration)); + status = s_memc_write_zval (intern, MEMC_OP_SET, NULL, key, Z_REFVAL(ref_val), expiration); + ZVAL_DUP(value, Z_REFVAL(ref_val)); } + } + else { + s_memc_set_status(intern, MEMCACHED_NOTFOUND, 0); + } - if (key->len > 0 && key->len < MEMCACHED_MAX_KEY) { - keys_out->mkeys[idx] = key->val; - keys_out->mkeys_len[idx] = key->len; - keys_out->strings[idx] = key; - idx++; - } - else { - zend_string_release (key); - } - } ZEND_HASH_FOREACH_END(); + zval_ptr_dtor(zobject); + zval_ptr_dtor(&zv_key); + zval_ptr_dtor(&ref_val); + zval_ptr_dtor(&ref_expiration); - if (!idx) { - efree (keys_out->mkeys); - efree (keys_out->mkeys_len); - efree (keys_out->strings); + if (!Z_ISUNDEF(retval)) { + zval_ptr_dtor(&retval); } - keys_out->num_valid_keys = idx; + return status; } -static -void s_clear_keys(php_memcached_keys *keys) -{ - size_t i; - for (i = 0; i < keys->num_valid_keys; i++) { - zend_string_release (keys->strings[i]); - } - efree(keys->strings); - efree(keys->mkeys); - efree(keys->mkeys_len); -} +/**************************************** + Wrapper for setting from zval +****************************************/ static -memcached_return s_memcached_get_multi(memcached_st *memc, HashTable *hash_keys, zend_string *server_key, zend_long get_flags, zval *return_value) +zend_bool s_compress_value (php_memc_compression_type compression_type, zend_string **payload_in, uint32_t *flags) { - php_memcached_keys keys = { 0 }; - zval values; - memcached_return rc, status = MEMCACHED_SUCCESS; - uint64_t orig_cas_flag; - memcached_result_st result; + /* status */ + zend_bool compress_status = 0; + zend_string *payload = *payload_in; - zend_bool extended = (get_flags & MEMC_GET_EXTENDED); - zend_bool preserve_order = (get_flags & MEMC_GET_PRESERVE_ORDER); + /* Additional 5% for the data */ + size_t buffer_size = (size_t) (((double) payload->len * 1.05) + 1.0); + char *buffer = emalloc(buffer_size); - array_init(&values); - s_hash_to_keys(&keys, hash_keys, preserve_order, &values); + /* Store compressed size here */ + size_t compressed_size = 0; + uint32_t original_size = payload->len; - if (!keys.num_valid_keys) { - zval_ptr_dtor(&values); - return MEMCACHED_NO_KEY_PROVIDED; - } + switch (compression_type) { - orig_cas_flag = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS); + case COMPRESSION_TYPE_FASTLZ: + { + compressed_size = fastlz_compress(payload->val, payload->len, buffer); - if (extended && !orig_cas_flag) { - memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1); - } + if (compressed_size > 0) { + compress_status = 1; + MEMC_VAL_SET_FLAG(*flags, MEMC_VAL_COMPRESSION_FASTLZ); + } + } + break; - if (server_key) { - status = memcached_mget_by_key(memc, server_key->val, server_key->len, keys.mkeys, keys.mkeys_len, keys.num_valid_keys); - } else { - status = memcached_mget(memc, keys.mkeys, keys.mkeys_len, keys.num_valid_keys); - } + case COMPRESSION_TYPE_ZLIB: + { + compressed_size = buffer_size; + int status = compress((Bytef *) buffer, &compressed_size, (Bytef *) payload->val, payload->len); - s_clear_keys(&keys); + if (status == Z_OK) { + compress_status = 1; + MEMC_VAL_SET_FLAG(*flags, MEMC_VAL_COMPRESSION_ZLIB); + } + } + break; - if (extended && !orig_cas_flag) { - memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 0); + default: + compress_status = 0; + break; } - memcached_result_create(memc, &result); - while ((memcached_fetch_result(memc, &result, &rc)) != NULL) { - - const char *res_key = NULL; - size_t res_key_len = 0; - zval value; - - /* For some reason instead of success it's end */ - if (rc == MEMCACHED_END) { - rc = MEMCACHED_SUCCESS; - } - - if (rc != MEMCACHED_SUCCESS) { - status = rc; - continue; - } + if (!compress_status) { + php_error_docref(NULL, E_WARNING, "could not compress value"); + MEMC_VAL_DEL_FLAG(*flags, MEMC_VAL_COMPRESSED); + efree (buffer); + return 0; + } - ZVAL_UNDEF(&value); - if (!s_memcached_result_to_zval(memc, &result, &value)) { - if (EG(exception)) { - status = MEMC_RES_PAYLOAD_FAILURE; + /* This means the value was too small to be compressed, still a success */ + if (compressed_size > (payload->len * MEMC_G(compression_factor))) { + MEMC_VAL_DEL_FLAG(*flags, MEMC_VAL_COMPRESSED); + efree (buffer); + return 1; + } - memcached_result_free(&result); - memcached_quit(memc); - zval_ptr_dtor (&values); - break; - } - status = MEMCACHED_SOME_ERRORS; - continue; - } + payload = zend_string_realloc(payload, compressed_size + sizeof(uint32_t), 0); - res_key = memcached_result_key_value(&result); - res_key_len = memcached_result_key_length(&result); + /* Copy the uin32_t at the beginning */ + memcpy(payload->val, &original_size, sizeof(uint32_t)); + memcpy(payload->val + sizeof (uint32_t), buffer, compressed_size); + efree(buffer); - if (extended) { - uint32_t flags; - uint64_t cas; - zval cas_token, node; + zend_string_forget_hash_val(payload); + *payload_in = payload; + return 1; +} - cas = memcached_result_cas(&result); - flags = memcached_result_flags(&result); +static +zend_bool s_serialize_value (php_memc_serializer_type serializer, zval *value, smart_str *buf, uint32_t *flags) +{ + switch (serializer) { - s_uint64_to_zval (&cas_token, cas); + /* + Igbinary serialization + */ +#ifdef HAVE_MEMCACHED_IGBINARY + case SERIALIZER_IGBINARY: + { + uint8_t *buffer; + size_t buffer_len; - array_init (&node); - add_assoc_zval (&node, "value", &value); - add_assoc_zval (&node, "cas", &cas_token); - add_assoc_long (&node, "flags", (zend_long) MEMC_VAL_GET_USER_FLAGS(flags)); + if (igbinary_serialize(&buffer, &buffer_len, value) != 0) { + php_error_docref(NULL, E_WARNING, "could not serialize value with igbinary"); + return 0; + } + smart_str_appendl (buf, buffer, buffer_len); + efree(buffer); + MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_IGBINARY); + } + break; +#endif - add_assoc_zval_ex(&values, res_key, res_key_len, &node); + /* + JSON serialization + */ +#ifdef HAVE_JSON_API + case SERIALIZER_JSON: + case SERIALIZER_JSON_ARRAY: + { + php_json_encode(buf, value, 0); + MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_JSON); } - else { - add_assoc_zval_ex(&values, res_key, res_key_len, &value); + break; +#endif + + /* + msgpack serialization + */ +#ifdef HAVE_MEMCACHED_MSGPACK + case SERIALIZER_MSGPACK: + php_msgpack_serialize(buf, value); + if (!buf->s) { + php_error_docref(NULL, E_WARNING, "could not serialize value with msgpack"); + return 0; + } + MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_MSGPACK); + break; +#endif + + /* + PHP serialization + */ + default: + { + php_serialize_data_t var_hash; + PHP_VAR_SERIALIZE_INIT(var_hash); + php_var_serialize(buf, value, &var_hash); + PHP_VAR_SERIALIZE_DESTROY(var_hash); + + if (!buf->s) { + php_error_docref(NULL, E_WARNING, "could not serialize value"); + return 0; + } + MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_SERIALIZED); } + break; } - memcached_result_free(&result); - if (Z_TYPE(values) != IS_UNDEF) { - ZVAL_ZVAL(return_value, &values, 0, 0); + /* Check for exceptions caused by serializers */ + if (EG(exception) && buf->s->len) { + return 0; } - return status; + return 1; } - static -void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) +zend_string *s_zval_to_payload(php_memc_object_t *intern, zval *value, uint32_t *flags) { - zend_long get_flags = 0; - zend_string *key; - zend_string *server_key = NULL; - memcached_return status = MEMCACHED_SUCCESS; - zend_fcall_info fci = empty_fcall_info; - zend_fcall_info_cache fcc = empty_fcall_info_cache; - HashTable keys; - zval values, tmp; - MEMC_METHOD_INIT_VARS; + zend_string *payload; + php_memc_user_data_t *memc_user_data = memcached_get_user_data(intern->memc); + zend_bool should_compress = memc_user_data->compression_enabled; - if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|f!l", &server_key, &key, &fci, &fcc, &get_flags) == FAILURE) { - return; - } - } else { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|f!l", &key, &fci, &fcc, &get_flags) == FAILURE) { - return; + switch (Z_TYPE_P(value)) { + + case IS_STRING: + payload = zval_get_string(value); + MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_STRING); + break; + + case IS_LONG: + { + smart_str buffer = {0}; + smart_str_append_long (&buffer, Z_LVAL_P(value)); + smart_str_0(&buffer); + payload = buffer.s; + + MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_LONG); + should_compress = 0; } - } + break; - MEMC_METHOD_FETCH_OBJECT; - intern->rescode = MEMCACHED_SUCCESS; + case IS_DOUBLE: + { + char buffer[40]; + php_memcached_g_fmt(buffer, Z_DVAL_P(value)); + payload = zend_string_init (buffer, strlen (buffer), 0); + MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_DOUBLE); + should_compress = 0; + } + break; - zend_hash_init (&keys, 1, 0, NULL, 0); - ZVAL_STR(&tmp, key); - zend_hash_add(&keys, key, &tmp); + case IS_TRUE: + payload = zend_string_init ("1", 1, 0); + MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_BOOL); + should_compress = 0; + break; - ZVAL_UNDEF(&values); - status = s_memcached_get_multi(intern->memc, &keys, server_key, get_flags, &values); - zend_hash_destroy (&keys); + case IS_FALSE: + payload = zend_string_alloc (0, 0); + MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_BOOL); + should_compress = 0; + break; - if (EG(exception)) { - zval_ptr_dtor(&values); - RETURN_FROM_GET; - } + default: + { + smart_str buffer = {0}; - if (status == MEMCACHED_SUCCESS) { - zval *zv = zend_hash_find (Z_ARRVAL(values), key); - if (zv) { - RETVAL_ZVAL(zv, 1, 0); - zval_ptr_dtor(&values); - return; - } - else { - status = MEMCACHED_NOTFOUND; + if (!s_serialize_value (memc_user_data->serializer, value, &buffer, flags)) { + smart_str_free(&buffer); + return NULL; + } + payload = buffer.s; } + break; } + zend_string_forget_hash_val(payload); - if (Z_TYPE(values) != IS_UNDEF) { - zval_ptr_dtor(&values); + /* turn off compression for values below the threshold */ + if (payload->len == 0 || payload->len < MEMC_G(compression_threshold)) { + should_compress = 0; } - if (status == MEMCACHED_NOTFOUND && fci.size > 0) { - // try to invoke cache cb - status = s_invoke_cache_callback(object, &fci, &fcc, key, return_value); + /* If we have compression flag, compress the value */ + if (should_compress) { + /* status */ + if (!s_compress_value (memc_user_data->compression_type, &payload, flags)) { + zend_string_release(payload); + return NULL; + } + MEMC_VAL_SET_FLAG(*flags, MEMC_VAL_COMPRESSED); } - if (php_memc_handle_error(intern, status) < 0) { - RETURN_FROM_GET; + if (memc_user_data->set_udf_flags >= 0) { + MEMC_VAL_SET_USER_FLAGS(*flags, ((uint32_t) memc_user_data->set_udf_flags)); } -} -/* {{{ Memcached::get(string key [, mixed callback [, int get_flags = 0]) - Returns a value for the given key or false */ -PHP_METHOD(Memcached, get) -{ - php_memc_get_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); + return payload; } -/* }}} */ -/* {{{ Memcached::getByKey(string server_key, string key [, mixed callback [, int get_flags = 0]) - Returns a value for key from the server identified by the server key or false */ -PHP_METHOD(Memcached, getByKey) +static +zend_bool s_should_retry_write (php_memc_object_t *intern, memcached_return status) { - php_memc_get_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); + if (memcached_server_count (intern->memc) == 0) { + return 0; + } + + return s_memcached_return_is_error (status, 1); } -/* }}} */ -/* {{{ -- php_memc_getMulti_impl */ -static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) +static +zend_bool s_memc_write_zval (php_memc_object_t *intern, php_memc_write_op op, zend_string *server_key, zend_string *key, zval *value, time_t expiration) { - zval *keys = NULL; - zend_string *server_key = NULL; - memcached_return rc; - zend_long flags = 0; - MEMC_METHOD_INIT_VARS; + uint32_t flags = 0; + zend_string *payload = NULL; + memcached_return status; + php_memc_user_data_t *memc_user_data = memcached_get_user_data(intern->memc); + zend_long retries = memc_user_data->store_retry_count; - if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa/|l", &server_key, - &keys, &flags) == FAILURE) { - return; - } - } else { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|l", &keys, &flags) == FAILURE) { - return; + if (value) { + payload = s_zval_to_payload(intern, value, &flags); + + if (!payload) { + s_memc_set_status(intern, MEMC_RES_PAYLOAD_FAILURE, 0); + return 0; } } - MEMC_METHOD_FETCH_OBJECT; +#define memc_write_using_fn(fn_name) payload ? fn_name(intern->memc, key->val, key->len, payload->val, payload->len, expiration, flags) : MEMC_RES_PAYLOAD_FAILURE; +#define memc_write_using_fn_by_key(fn_name) payload ? fn_name(intern->memc, server_key->val, server_key->len, key->val, key->len, payload->val, payload->len, expiration, flags) : MEMC_RES_PAYLOAD_FAILURE; - rc = s_memcached_get_multi(intern->memc, Z_ARRVAL_P(keys), server_key, flags, return_value); - php_memc_handle_error(intern, rc); + if (server_key) { + switch (op) { + case MEMC_OP_SET: + status = memc_write_using_fn_by_key(memcached_set_by_key); + break; - if (EG(exception)) { - zval_dtor(return_value); - RETURN_FALSE; - } -} -/* }}} */ + case MEMC_OP_TOUCH: + status = memcached_touch_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, expiration); + break; + + case MEMC_OP_ADD: + status = memc_write_using_fn_by_key(memcached_add_by_key); + break; + + case MEMC_OP_REPLACE: + status = memc_write_using_fn_by_key(memcached_replace_by_key); + break; + + case MEMC_OP_APPEND: + status = memc_write_using_fn_by_key(memcached_append_by_key); + break; -/* {{{ Memcached::getMulti(array keys[, long flags = 0 ]) - Returns values for the given keys or false */ -PHP_METHOD(Memcached, getMulti) -{ - php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); -} -/* }}} */ + case MEMC_OP_PREPEND: + status = memc_write_using_fn_by_key(memcached_prepend_by_key); + break; + } -/* {{{ Memcached::getMultiByKey(string server_key, array keys[, long flags = 0 ]) - Returns values for the given keys from the server identified by the server key or false */ -PHP_METHOD(Memcached, getMultiByKey) -{ - php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); -} -/* }}} */ + if (status == MEMCACHED_END) { + status = MEMCACHED_SUCCESS; + } + } + else { +retry: + switch (op) { + case MEMC_OP_SET: + status = memc_write_using_fn(memcached_set); + break; -/* {{{ Memcached::getDelayed(array keys [, bool with_cas [, mixed callback ] ]) - Sends a request for the given keys and returns immediately */ -PHP_METHOD(Memcached, getDelayed) -{ - php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); -} -/* }}} */ - -/* {{{ Memcached::getDelayedByKey(string server_key, array keys [, bool with_cas [, mixed callback ] ]) - Sends a request for the given keys from the server identified by the server key and returns immediately */ -PHP_METHOD(Memcached, getDelayedByKey) -{ - php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); -} -/* }}} */ - -/* {{{ -- php_memc_getDelayed_impl */ -static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) -{ - zval *keys = NULL; - zend_string *server_key = NULL; - zend_bool with_cas = 0; - size_t num_keys = 0; - zval *entry = NULL; - const char **mkeys = NULL; - size_t *mkeys_len = NULL; - uint64_t orig_cas_flag = 0; - zend_fcall_info fci = empty_fcall_info; - zend_fcall_info_cache fcc = empty_fcall_info_cache; - int i = 0; - memcached_return status = MEMCACHED_SUCCESS; - MEMC_METHOD_INIT_VARS; + case MEMC_OP_TOUCH: + status = memcached_touch(intern->memc, key->val, key->len, expiration); + break; + + case MEMC_OP_ADD: + status = memc_write_using_fn(memcached_add); + break; + + case MEMC_OP_REPLACE: + status = memc_write_using_fn(memcached_replace); + break; + + case MEMC_OP_APPEND: + status = memc_write_using_fn(memcached_append); + break; - if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa/|bf!", &server_key, - &keys, &with_cas, &fci, &fcc) == FAILURE) { - return; + case MEMC_OP_PREPEND: + status = memc_write_using_fn(memcached_prepend); + break; } - } else { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|bf!", &keys, &with_cas, - &fci, &fcc) == FAILURE) { - return; + if (status == MEMCACHED_END) { + status = MEMCACHED_SUCCESS; } } - MEMC_METHOD_FETCH_OBJECT; - intern->rescode = MEMCACHED_SUCCESS; - - /* - * Create the array of keys for libmemcached. If none of the keys were valid - * (strings), set bad key result code and return. - */ - num_keys = zend_hash_num_elements(Z_ARRVAL_P(keys)); - mkeys = safe_emalloc(num_keys, sizeof(*mkeys), 0); - mkeys_len = safe_emalloc(num_keys, sizeof(*mkeys_len), 0); - - ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(keys), entry) { - if (Z_TYPE_P(entry) != IS_STRING) { - convert_to_string_ex(entry); - } - - if (Z_TYPE_P(entry) == IS_STRING && Z_STRLEN_P(entry) > 0) { - mkeys[i] = Z_STRVAL_P(entry); - mkeys_len[i] = Z_STRLEN_P(entry); - i++; - } - } ZEND_HASH_FOREACH_END(); - - if (i == 0) { - intern->rescode = MEMCACHED_BAD_KEY_PROVIDED; - efree(mkeys); - efree(mkeys_len); - zval_dtor(return_value); - RETURN_FALSE; + if (s_should_retry_write (intern, status) && retries-- > 0) { + goto retry; } - /* - * Enable CAS support, but only if it is currently disabled. - */ - if (with_cas) { - orig_cas_flag = memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS); - if (orig_cas_flag == 0) { - memcached_behavior_set(intern->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1); - } - } +#undef memc_write_using_fn +#undef memc_write_using_fn_by_key - /* - * Issue the request, but collect results only if the result callback is provided. - */ - if (by_key) { - status = memcached_mget_by_key(intern->memc, server_key->val, server_key->len, mkeys, mkeys_len, i); - } else { - status = memcached_mget(intern->memc, mkeys, mkeys_len, i); + if (payload) { + zend_string_release(payload); } - /* - * Restore the CAS support flag, but only if we had to turn it on. - */ - if (with_cas && orig_cas_flag == 0) { - memcached_behavior_set(intern->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, orig_cas_flag); + if (s_memc_status_handle_result_code(intern, status) == FAILURE) { + return 0; } + return 1; +} - efree(mkeys); - efree(mkeys_len); - if (php_memc_handle_error(intern, status) < 0) { - zval_dtor(return_value); - RETURN_FALSE; - } - if (fci.size != 0) { - /* - * We have a result callback. Iterate through the result set and invoke the - * callback for each one. - */ - memcached_result_st result; +/**************************************** + Methods +****************************************/ - memcached_result_create(intern->memc, &result); - while ((memcached_fetch_result(intern->memc, &result, &status)) != NULL) { - if (s_invoke_result_callback(getThis(), &fci, &fcc, &result) < 0) { - status = MEMCACHED_FAILURE; - break; - } - } - memcached_result_free(&result); - /* we successfully retrieved all rows */ - if (status == MEMCACHED_END) { - status = MEMCACHED_SUCCESS; - } - if (php_memc_handle_error(intern, status) < 0) { - RETURN_FALSE; - } - } +/* {{{ Memcached::__construct([string persistent_id[, callback on_new[, string connection_str]]])) + Creates a Memcached object, optionally using persistent memcache connection */ +static PHP_METHOD(Memcached, __construct) +{ + php_memc_object_t *intern; + php_memc_user_data_t *memc_user_data; - RETURN_TRUE; -} -/* }}} */ + zend_string *persistent_id = NULL; + zend_string *conn_str = NULL; + zend_string *plist_key = NULL; + zend_fcall_info fci = {0}; + zend_fcall_info_cache fci_cache; -/* {{{ Memcached::fetch() - Returns the next result from a previous delayed request */ -PHP_METHOD(Memcached, fetch) -{ - const char *res_key = NULL; - size_t res_key_len = 0; - const char *payload = NULL; - size_t payload_len = 0; - uint32_t flags = 0; - uint64_t cas = 0; - zval value, zv_cas; - memcached_result_st result; - memcached_return status = MEMCACHED_SUCCESS; - MEMC_METHOD_INIT_VARS; + zend_bool is_persistent = 0; - if (zend_parse_parameters_none() == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!f!S", &persistent_id, &fci, &fci_cache, &conn_str) == FAILURE) { return; } - MEMC_METHOD_FETCH_OBJECT; - intern->rescode = MEMCACHED_SUCCESS; + intern = Z_MEMC_OBJ_P(getThis()); + intern->is_pristine = 1; - memcached_result_create(intern->memc, &result); - if ((memcached_fetch_result(intern->memc, &result, &status)) == NULL) { - php_memc_handle_error(intern, status); - memcached_result_free(&result); - RETURN_FALSE; + if (persistent_id && persistent_id->len) { + zend_resource *le; + + plist_key = zend_string_alloc(sizeof("memcached:id=") + persistent_id->len - 1, 0); + snprintf(plist_key->val, plist_key->len + 1, "memcached:id=%s", persistent_id->val); + + if ((le = zend_hash_find_ptr(&EG(persistent_list), plist_key)) != NULL) { + if (le->type == php_memc_list_entry()) { + intern->memc = le->ptr; + intern->is_pristine = 0; + zend_string_release (plist_key); + return; + } + } + is_persistent = 1; } - if (!s_memcached_result_to_zval(intern->memc, &result, &value)) { - memcached_result_free(&result); - intern->rescode = MEMC_RES_PAYLOAD_FAILURE; - RETURN_FALSE; + if (conn_str && conn_str->len > 0) { + intern->memc = memcached (conn_str->val, conn_str->len); + } + else { + intern->memc = memcached (NULL, 0); } - array_init(return_value); + if (!intern->memc) { + // TODO: handle allocation fail + } + + memc_user_data = pecalloc (1, sizeof(*memc_user_data), is_persistent); + memc_user_data->serializer = MEMC_G(serializer_type); + memc_user_data->compression_type = MEMC_G(compression_type); + memc_user_data->compression_enabled = 1; + memc_user_data->store_retry_count = MEMC_G(store_retry_count); + memc_user_data->set_udf_flags = -1; + memc_user_data->is_persistent = is_persistent; + + memcached_set_user_data(intern->memc, memc_user_data); + + if (fci.size) { + if (!s_invoke_new_instance_cb(getThis(), &fci, &fci_cache, persistent_id) || EG(exception)) { + /* error calling or exception thrown from callback */ + if (plist_key) { + zend_string_release(plist_key); + } + /* + Setting intern->memc null prevents object destruction from freeing the memcached_st + We free it manually here because it might be persistent and has not been + registered to persistent_list yet + */ + php_memc_destroy(intern->memc, memc_user_data); + intern->memc = NULL; + return; + } + } - flags = memcached_result_flags(&result); - res_key = memcached_result_key_value(&result); - res_key_len = memcached_result_key_length(&result); - cas = memcached_result_cas(&result); + if (plist_key) { + zend_resource le; - add_assoc_stringl_ex(return_value, ZEND_STRL("key"), (char *) res_key, res_key_len); - add_assoc_zval_ex(return_value, ZEND_STRL("value"), &value); + le.type = php_memc_list_entry(); + le.ptr = intern->memc; - s_uint64_to_zval (&zv_cas, cas); - add_assoc_zval_ex(return_value, ZEND_STRL("cas"), &zv_cas); - add_assoc_long_ex(return_value, ZEND_STRL("flags"), MEMC_VAL_GET_USER_FLAGS(flags)); + GC_REFCOUNT(&le) = 1; - memcached_result_free(&result); + /* plist_key is not a persistent allocated key, thus we use str_update here */ + if (zend_hash_str_update_mem(&EG(persistent_list), plist_key->val, plist_key->len, &le, sizeof(le)) == NULL) { + zend_string_release(plist_key); + php_error_docref(NULL, E_ERROR, "could not register persistent entry"); + /* not reached */ + } + zend_string_release(plist_key); + } } /* }}} */ -/* {{{ Memcached::fetchAll() - Returns all the results from a previous delayed request */ -PHP_METHOD(Memcached, fetchAll) + + +static +void s_hash_to_keys(php_memc_keys_t *keys_out, HashTable *hash_in, zend_bool preserve_order, zval *return_value) { - const char *res_key = NULL; - size_t res_key_len = 0; - const char *payload = NULL; - size_t payload_len = 0; - uint32_t flags; - uint64_t cas = 0; - zval value, entry, zv_cas; - memcached_result_st result; - memcached_return status = MEMCACHED_SUCCESS; - MEMC_METHOD_INIT_VARS; + size_t idx = 0, alloc_count; + zval *zv; - if (zend_parse_parameters_none() == FAILURE) { + keys_out->num_valid_keys = 0; + + alloc_count = zend_hash_num_elements(hash_in); + if (!alloc_count) { return; } + keys_out->mkeys = ecalloc (alloc_count, sizeof (char *)); + keys_out->mkeys_len = ecalloc (alloc_count, sizeof (size_t)); + keys_out->strings = ecalloc (alloc_count, sizeof (zend_string *)); - MEMC_METHOD_FETCH_OBJECT; - intern->rescode = MEMCACHED_SUCCESS; + ZEND_HASH_FOREACH_VAL(hash_in, zv) { + zend_string *key = zval_get_string(zv); - array_init(return_value); - memcached_result_create(intern->memc, &result); + if (preserve_order && return_value) { + add_assoc_null_ex(return_value, key->val, key->len); + } - while ((memcached_fetch_result(intern->memc, &result, &status)) != NULL) { + if (key->len > 0 && key->len < MEMCACHED_MAX_KEY) { + keys_out->mkeys[idx] = key->val; + keys_out->mkeys_len[idx] = key->len; - if (!s_memcached_result_to_zval(intern->memc, &result, &value)) { - memcached_result_free(&result); - zval_dtor(return_value); - intern->rescode = MEMC_RES_PAYLOAD_FAILURE; - RETURN_FALSE; + keys_out->strings[idx] = key; + idx++; + } + else { + zend_string_release (key); } - flags = memcached_result_flags(&result); - res_key = memcached_result_key_value(&result); - res_key_len = memcached_result_key_length(&result); - cas = memcached_result_cas(&result); + } ZEND_HASH_FOREACH_END(); - array_init(&entry); - add_assoc_stringl_ex(&entry, ZEND_STRL("key"), (char *)res_key, res_key_len); - add_assoc_zval_ex(&entry, ZEND_STRL("value"), &value); + if (!idx) { + efree (keys_out->mkeys); + efree (keys_out->mkeys_len); + efree (keys_out->strings); + } + keys_out->num_valid_keys = idx; +} - s_uint64_to_zval (&zv_cas, cas); - add_assoc_zval_ex(&entry, ZEND_STRL("cas"), &zv_cas); - add_assoc_long_ex(&entry, ZEND_STRL("flags"), MEMC_VAL_GET_USER_FLAGS(flags)); +static +void s_key_to_keys(php_memc_keys_t *keys_out, zend_string *key) +{ + zval zv_keys; - add_next_index_zval(return_value, &entry); - } + array_init (&zv_keys); + add_next_index_stringl (&zv_keys, key->val, key->len); - memcached_result_free(&result); + s_hash_to_keys(keys_out, Z_ARRVAL(zv_keys), 0, NULL); + zval_ptr_dtor(&zv_keys); +} - if (status != MEMCACHED_END && php_memc_handle_error(intern, status) < 0) { - zval_dtor(return_value); - RETURN_FALSE; +static +void s_clear_keys(php_memc_keys_t *keys) +{ + size_t i; + for (i = 0; i < keys->num_valid_keys; i++) { + zend_string_release (keys->strings[i]); } + efree(keys->strings); + efree(keys->mkeys); + efree(keys->mkeys_len); } -/* }}} */ -/* {{{ Memcached::set(string key, mixed value [, int expiration ]) - Sets the value for the given key */ -PHP_METHOD(Memcached, set) -{ - php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_SET, 0); -} -/* }}} */ +typedef struct { + zend_bool extended; + zval *return_value; +} php_memc_get_ctx_t; -/* {{{ Memcached::setByKey(string server_key, string key, mixed value [, int expiration ]) - Sets the value for the given key on the server identified by the server key */ -PHP_METHOD(Memcached, setByKey) +static +zend_bool s_get_apply_fn(php_memc_object_t *intern, zend_string *key, zval *value, zval *cas, uint32_t flags, void *in_context) { - php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_SET, 1); + php_memc_get_ctx_t *context = (php_memc_get_ctx_t *) in_context; + + if (context->extended) { + Z_TRY_ADDREF_P(value); + Z_TRY_ADDREF_P(cas); + + array_init (context->return_value); + add_assoc_zval (context->return_value, "value", value); + add_assoc_zval (context->return_value, "cas", cas); + add_assoc_long (context->return_value, "flags", (zend_long) MEMC_VAL_GET_USER_FLAGS(flags)); + } + else { + ZVAL_ZVAL(context->return_value, value, 1, 0); + } + return 0; /* Stop after one */ } -/* }}} */ -#ifdef HAVE_MEMCACHED_TOUCH -/* {{{ Memcached::touch(string key, [, int expiration ]) - Sets a new expiration for the given key */ -PHP_METHOD(Memcached, touch) +static +void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { - php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_TOUCH, 0); + php_memc_get_ctx_t context = {}; + php_memc_keys_t keys = {0}; + zend_long get_flags = 0; + zend_string *key; + zend_string *server_key = NULL; + zend_bool extended, mget_status; + memcached_return status = MEMCACHED_SUCCESS; + zend_fcall_info fci = empty_fcall_info; + zend_fcall_info_cache fcc = empty_fcall_info_cache; + MEMC_METHOD_INIT_VARS; + + if (by_key) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|f!l", &server_key, &key, &fci, &fcc, &get_flags) == FAILURE) { + return; + } + } else { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|f!l", &key, &fci, &fcc, &get_flags) == FAILURE) { + return; + } + } + + MEMC_METHOD_FETCH_OBJECT; + s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); + + context.extended = (get_flags & MEMC_GET_EXTENDED); + + ZVAL_UNDEF(return_value); + context.return_value = return_value; + + s_key_to_keys(&keys, key); + mget_status = php_memc_mget_apply(intern, server_key, &keys, s_get_apply_fn, context.extended, &context); + s_clear_keys(&keys); + + if (!mget_status) { + if (s_memc_status_has_result_code(intern, MEMCACHED_NOTFOUND) && fci.size > 0) { + status = s_invoke_cache_callback(object, &fci, &fcc, key, return_value); + + if (!status) { + zval_ptr_dtor(return_value); + RETURN_FROM_GET; + } + } + } + + if (s_memc_status_has_error(intern)) { + zval_ptr_dtor(return_value); + RETURN_FROM_GET; + } } -/* }}} */ -/* {{{ Memcached::touchbyKey(string key, [, int expiration ]) - Sets a new expiration for the given key */ -PHP_METHOD(Memcached, touchByKey) +/* {{{ Memcached::get(string key [, mixed callback [, int get_flags = 0]) + Returns a value for the given key or false */ +PHP_METHOD(Memcached, get) { - php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_TOUCH, 1); + php_memc_get_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); } /* }}} */ -#endif - -/* {{{ Memcached::setMulti(array items [, int expiration ]) - Sets the keys/values specified in the items array */ -PHP_METHOD(Memcached, setMulti) +/* {{{ Memcached::getByKey(string server_key, string key [, mixed callback [, int get_flags = 0]) + Returns a value for key from the server identified by the server key or false */ +PHP_METHOD(Memcached, getByKey) { - php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); + php_memc_get_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); } /* }}} */ -/* {{{ Memcached::setMultiByKey(string server_key, array items [, int expiration ]) - Sets the keys/values specified in the items array on the server identified by the given server key */ -PHP_METHOD(Memcached, setMultiByKey) +static +zend_bool s_get_multi_apply_fn(php_memc_object_t *intern, zend_string *key, zval *value, zval *cas, uint32_t flags, void *in_context) { - php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); -} -/* }}} */ + php_memc_get_ctx_t *context = (php_memc_get_ctx_t *) in_context; + + Z_TRY_ADDREF_P(value); + + if (context->extended) { + zval node; + + Z_TRY_ADDREF_P(cas); + + array_init (&node); + add_assoc_zval (&node, "value", value); + add_assoc_zval (&node, "cas", cas); + add_assoc_long (&node, "flags", (zend_long) MEMC_VAL_GET_USER_FLAGS(flags)); -#define PHP_MEMC_FAILOVER_RETRY \ - if (!by_key && retry < memc_user_data->store_retry_count) { \ - switch (intern->rescode) { \ - case MEMCACHED_HOST_LOOKUP_FAILURE: \ - case MEMCACHED_CONNECTION_FAILURE: \ - case MEMCACHED_CONNECTION_BIND_FAILURE: \ - case MEMCACHED_WRITE_FAILURE: \ - case MEMCACHED_READ_FAILURE: \ - case MEMCACHED_UNKNOWN_READ_FAILURE: \ - case MEMCACHED_PROTOCOL_ERROR: \ - case MEMCACHED_SERVER_ERROR: \ - case MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE: \ - case MEMCACHED_TIMEOUT: \ - case MEMCACHED_FAIL_UNIX_SOCKET: \ - case MEMCACHED_SERVER_MARKED_DEAD: \ - case MEMCACHED_SERVER_TEMPORARILY_DISABLED: \ - if (memcached_server_count(intern->memc) > 0) { \ - retry++; \ - intern->rescode = 0; \ - goto retry; \ - } \ - break; \ - } \ + add_assoc_zval_ex(context->return_value, key->val, key->len, &node); } + else { + add_assoc_zval_ex(context->return_value, key->val, key->len, value); + } + return 1; +} -/* {{{ -- php_memc_setMulti_impl */ -static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) +/* {{{ -- php_memc_getMulti_impl */ +static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { - zval *entries; + php_memc_get_ctx_t context; + php_memc_keys_t keys_out; + + zval *keys = NULL; zend_string *server_key = NULL; - time_t expiration = 0; - zval *value; - zend_string *skey, *str_key = NULL; - ulong num_key; - zend_string *payload; - uint32_t flags = 0; - uint32_t retry = 0; - memcached_return status; - char tmp_key[MEMCACHED_MAX_KEY]; - int tmp_len = 0; + zend_long flags = 0; MEMC_METHOD_INIT_VARS; + zend_bool with_cas, retval, preserve_order, extended; + if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa|ll", &server_key, - &entries, &expiration) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa|l", &server_key, + &keys, &flags) == FAILURE) { return; } } else { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|ll", &entries, &expiration) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|l", &keys, &flags) == FAILURE) { return; } } MEMC_METHOD_FETCH_OBJECT; - intern->rescode = MEMCACHED_SUCCESS; + s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); - ZEND_HASH_FOREACH_KEY_VAL (Z_ARRVAL_P(entries), num_key, skey, value) { - if (skey) { - str_key = skey; - } else if (num_key || num_key == 0) { - /* Array keys are unsigned, but php integers are signed. - * Keys must be converted to signed strings that match - * php integers. */ - assert(sizeof(tmp_key) >= sizeof(ZEND_TOSTR(LONG_MIN))); - tmp_len = sprintf(tmp_key, "%ld", (long)num_key); - str_key = zend_string_init(tmp_key, tmp_len, 0); - } else { - continue; - } + array_init(return_value); - flags = 0; - if (memc_user_data->compression) { - MEMC_VAL_SET_FLAG(flags, MEMC_VAL_COMPRESSED); - } + preserve_order = (flags & MEMC_GET_PRESERVE_ORDER); + s_hash_to_keys(&keys_out, Z_ARRVAL_P(keys), preserve_order, return_value); - if (memc_user_data->set_udf_flags >= 0) { - MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) memc_user_data->set_udf_flags)); - } + context.extended = (flags & MEMC_GET_EXTENDED); + context.return_value = return_value; - payload = s_zval_to_payload(value, &flags, memc_user_data->serializer, memc_user_data->compression_type); - if (payload == NULL) { - intern->rescode = MEMC_RES_PAYLOAD_FAILURE; - if (!skey) { - zend_string_release(str_key); - } - RETURN_FALSE; - } + retval = php_memc_mget_apply(intern, server_key, &keys_out, s_get_multi_apply_fn, context.extended, &context); -retry: - if (!by_key) { - status = memcached_set(intern->memc, str_key->val, str_key->len, payload->val, payload->len, expiration, flags); - } else { - status = memcached_set_by_key(intern->memc, server_key->val, server_key->len, str_key->val, str_key->len, payload->val, payload->len, expiration, flags); - } + s_clear_keys(&keys_out); - if (php_memc_handle_error(intern, status) < 0) { - PHP_MEMC_FAILOVER_RETRY - if (!skey) { - zend_string_release(str_key); - } - zend_string_release(payload); - RETURN_FALSE; - } - if (!skey) { - zend_string_release(str_key); - } - zend_string_release(payload); - } ZEND_HASH_FOREACH_END(); + if (!retval && (s_memc_status_has_result_code(intern, MEMCACHED_NOTFOUND) || s_memc_status_has_result_code(intern, MEMCACHED_SOME_ERRORS))) { + return; + } - RETURN_TRUE; + if (!retval || EG(exception)) { + zval_dtor(return_value); + RETURN_FROM_GET; + } } /* }}} */ -/* {{{ Memcached::add(string key, mixed value [, int expiration ]) - Sets the value for the given key, failing if the key already exists */ -PHP_METHOD(Memcached, add) +/* {{{ Memcached::getMulti(array keys[, long flags = 0 ]) + Returns values for the given keys or false */ +PHP_METHOD(Memcached, getMulti) { - php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_ADD, 0); + php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); } /* }}} */ -/* {{{ Memcached::addByKey(string server_key, string key, mixed value [, int expiration ]) - Sets the value for the given key on the server identified by the sever key, failing if the key already exists */ -PHP_METHOD(Memcached, addByKey) +/* {{{ Memcached::getMultiByKey(string server_key, array keys[, long flags = 0 ]) + Returns values for the given keys from the server identified by the server key or false */ +PHP_METHOD(Memcached, getMultiByKey) { - php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_ADD, 1); + php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); } /* }}} */ -/* {{{ Memcached::append(string key, mixed value) - Appends the value to existing one for the key */ -PHP_METHOD(Memcached, append) +/* {{{ Memcached::getDelayed(array keys [, bool with_cas [, mixed callback ] ]) + Sends a request for the given keys and returns immediately */ +PHP_METHOD(Memcached, getDelayed) { - php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_APPEND, 0); + php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); } /* }}} */ -/* {{{ Memcached::appendByKey(string server_key, string key, mixed value) - Appends the value to existing one for the key on the server identified by the server key */ -PHP_METHOD(Memcached, appendByKey) +/* {{{ Memcached::getDelayedByKey(string server_key, array keys [, bool with_cas [, mixed callback ] ]) + Sends a request for the given keys from the server identified by the server key and returns immediately */ +PHP_METHOD(Memcached, getDelayedByKey) { - php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_APPEND, 1); + php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); } /* }}} */ -/* {{{ Memcached::prepend(string key, mixed value) - Prepends the value to existing one for the key */ -PHP_METHOD(Memcached, prepend) -{ - php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_PREPEND, 0); -} -/* }}} */ -/* {{{ Memcached::prependByKey(string server_key, string key, mixed value) - Prepends the value to existing one for the key on the server identified by the server key */ -PHP_METHOD(Memcached, prependByKey) +static +void s_create_result_array(zend_string *key, zval *value, zval *cas, uint32_t flags, zval *return_value) { - php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_PREPEND, 1); -} -/* }}} */ + Z_TRY_ADDREF_P(value); + Z_TRY_ADDREF_P(cas); -/* {{{ Memcached::replace(string key, mixed value [, int expiration ]) - Replaces the value for the given key, failing if the key doesn't exist */ -PHP_METHOD(Memcached, replace) -{ - php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_REPLACE, 0); + add_assoc_stringl_ex(return_value, ZEND_STRL("key"), key->val, key->len); + add_assoc_zval_ex(return_value, ZEND_STRL("value"), value); + + add_assoc_zval_ex(return_value, ZEND_STRL("cas"), cas); + add_assoc_long_ex(return_value, ZEND_STRL("flags"), MEMC_VAL_GET_USER_FLAGS(flags)); } -/* }}} */ -/* {{{ Memcached::replaceByKey(string server_key, string key, mixed value [, int expiration ]) - Replaces the value for the given key on the server identified by the server key, failing if the key doesn't exist */ -PHP_METHOD(Memcached, replaceByKey) +static +zend_bool s_result_callback_apply(php_memc_object_t *intern, zend_string *key, zval *value, zval *cas, uint32_t flags, void *in_context) { - php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_REPLACE, 1); + zend_bool status = 1; + + zval retval, zv_result; + php_memc_result_callback_ctx_t *context = (php_memc_result_callback_ctx_t *) in_context; + + array_init(&zv_result); + s_create_result_array(key, value, cas, flags, &zv_result); + + zend_fcall_info_argn(&context->fci, 2, context->object, &zv_result); + + context->fci.retval = &retval; + context->fci.param_count = 2; + + ZVAL_UNDEF(&retval); + if (zend_call_function(&context->fci, &context->fcc) == FAILURE) { + if (Z_TYPE(retval) != IS_UNDEF) { + zval_ptr_dtor(&retval); + } + php_error_docref(NULL, E_WARNING, "could not invoke result callback"); + status = 0; + } + + if (Z_TYPE(retval) != IS_UNDEF) { + zval_ptr_dtor(&retval); + } + + zend_fcall_info_args_clear(&context->fci, 2); + zval_ptr_dtor(&zv_result); + return status; } -/* }}} */ -/* {{{ -- php_memc_store_impl */ -static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool by_key) +/* {{{ -- php_memc_getDelayed_impl */ +static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { - zend_string *key; + php_memc_keys_t keys_out = {0}; + + zval *keys = NULL; zend_string *server_key = NULL; - zend_string *s_value; - zval s_zvalue; - zval *value; - zend_long expiration = 0; - zend_string *payload = NULL; - uint32_t flags = 0; - uint32_t retry = 0; - memcached_return status; + zend_bool with_cas = 0; + + zend_fcall_info fci = empty_fcall_info; + zend_fcall_info_cache fcc = empty_fcall_info_cache; + memcached_return status = MEMCACHED_SUCCESS; MEMC_METHOD_INIT_VARS; + if (by_key) { - if (op == MEMC_OP_APPEND || op == MEMC_OP_PREPEND) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSS", &server_key, &key, &s_value) == FAILURE) { - return; - } - value = &s_zvalue; - ZVAL_STR(value, s_value); - } else if (op == MEMC_OP_TOUCH) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|l", &server_key, &key, &expiration) == FAILURE) { - return; - } - } else { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSz|l", &server_key, &key, &value, &expiration) == FAILURE) { - return; - } - } + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa/|bf!", &server_key, + &keys, &with_cas, &fci, &fcc) == FAILURE) { + return; + } } else { - if (op == MEMC_OP_APPEND || op == MEMC_OP_PREPEND) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &key, &s_value) == FAILURE) { - return; - } - value = &s_zvalue; - ZVAL_STR(value, s_value); - } else if (op == MEMC_OP_TOUCH) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|l", &key, &expiration) == FAILURE) { - return; - } - } else { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|l", &key, &value, &expiration) == FAILURE) { - return; - } + if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|bf!", &keys, &with_cas, + &fci, &fcc) == FAILURE) { + return; } } MEMC_METHOD_FETCH_OBJECT; - intern->rescode = MEMCACHED_SUCCESS; - - if (memc_user_data->compression) { - /* - * When compression is enabled, we cannot do appends/prepends because that would - * corrupt the compressed values. It is up to the user to fetch the value, - * append/prepend new data, and store it again. - */ - if (op == MEMC_OP_APPEND || op == MEMC_OP_PREPEND) { - php_error_docref(NULL, E_WARNING, "cannot append/prepend with compression turned on"); - return; - } - MEMC_VAL_SET_FLAG(flags, MEMC_VAL_COMPRESSED); - } + s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); - /* - * php_memcached uses 16 bits internally to store type, compression and serialization info. - * We use 16 upper bits to store user defined flags. - */ - if (memc_user_data->set_udf_flags >= 0) { - MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) memc_user_data->set_udf_flags)); - } + s_hash_to_keys(&keys_out, Z_ARRVAL_P(keys), 0, NULL); - if (op == MEMC_OP_TOUCH) { -#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x01000016 - if (memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) { - php_error_docref(NULL, E_WARNING, "using touch command with binary protocol is not recommended with libmemcached versions below 1.0.16"); - } -#endif + if (fci.size > 0) { + php_memc_result_callback_ctx_t context = { + getThis(), fci, fcc + }; + status = php_memc_mget_apply(intern, server_key, &keys_out, &s_result_callback_apply, with_cas, (void *) &context); } else { - payload = s_zval_to_payload(value, &flags, memc_user_data->serializer, memc_user_data->compression_type); - if (payload == NULL) { - intern->rescode = MEMC_RES_PAYLOAD_FAILURE; - RETURN_FALSE; - } + status = php_memc_mget_apply(intern, server_key, &keys_out, NULL, with_cas, NULL); } -retry: - switch (op) { - case MEMC_OP_SET: - if (!server_key) { - status = memcached_set(intern->memc, key->val, key->len, payload->val, payload->len, expiration, flags); - } else { - status = memcached_set_by_key(intern->memc, server_key->val, server_key->len, key->val, - key->len, payload->val, payload->len, expiration, flags); - } - break; -#ifdef HAVE_MEMCACHED_TOUCH - case MEMC_OP_TOUCH: - if (!server_key) { - status = memcached_touch(intern->memc, key->val, key->len, expiration); - } else { - status = memcached_touch_by_key(intern->memc, server_key->val, server_key->len, key->val, - key->len, expiration); - } - break; -#endif - case MEMC_OP_ADD: - if (!server_key) { - status = memcached_add(intern->memc, key->val, key->len, payload->val, payload->len, expiration, flags); - } else { - status = memcached_add_by_key(intern->memc, server_key->val, server_key->len, key->val, - key->len, payload->val, payload->len, expiration, flags); - } - break; - - case MEMC_OP_REPLACE: - if (!server_key) { - status = memcached_replace(intern->memc, key->val, key->len, payload->val, payload->len, expiration, flags); - } else { - status = memcached_replace_by_key(intern->memc, server_key->val, server_key->len, key->val, - key->len, payload->val, payload->len, expiration, flags); - } - break; - - case MEMC_OP_APPEND: - if (!server_key) { - status = memcached_append(intern->memc, key->val, key->len, payload->val, payload->len, expiration, flags); - } else { - status = memcached_append_by_key(intern->memc, server_key->val, server_key->len, key->val, - key->len, payload->val, payload->len, expiration, flags); - } - break; - - case MEMC_OP_PREPEND: - if (!server_key) { - status = memcached_prepend(intern->memc, key->val, key->len, payload->val, payload->len, expiration, flags); - } else { - status = memcached_prepend_by_key(intern->memc, server_key->val, server_key->len, key->val, - key->len, payload->val, payload->len, expiration, flags); - } - break; - default: - /* not reached */ - status = 0; - assert(0); - break; - } + s_clear_keys(&keys_out); + RETURN_BOOL(status); +} +/* }}} */ - if (php_memc_handle_error(intern, status) < 0) { - PHP_MEMC_FAILOVER_RETRY - RETVAL_FALSE; - } else { - RETVAL_TRUE; - } +static +zend_bool s_fetch_apply(php_memc_object_t *intern, zend_string *key, zval *value, zval *cas, uint32_t flags, void *in_context) +{ + zval *return_value = (zval *) in_context; + s_create_result_array(key, value, cas, flags, return_value); - if (payload) { - zend_string_release(payload); - } + return 0; // stop iterating after one } -/* }}} */ -/* {{{ -- php_memc_cas_impl */ -static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) +/* {{{ Memcached::fetch() + Returns the next result from a previous delayed request */ +PHP_METHOD(Memcached, fetch) { - zval *zv_cas; - uint64_t cas; - zend_string *key; - zend_string *server_key = NULL; - zval *value; - time_t expiration = 0; - zend_string *payload; + const char *res_key = NULL; + size_t res_key_len = 0; + const char *payload = NULL; + size_t payload_len = 0; uint32_t flags = 0; - memcached_return status; + uint64_t cas = 0; + zval value, zv_cas; + memcached_result_st result; + memcached_return status = MEMCACHED_SUCCESS; MEMC_METHOD_INIT_VARS; - if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zSSz|ll", &zv_cas, &server_key, &key, - &value, &expiration) == FAILURE) { - return; - } - } else { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zSz|ll", &zv_cas, &key, &value, - &expiration) == FAILURE) { - return; - } + if (zend_parse_parameters_none() == FAILURE) { + return; } MEMC_METHOD_FETCH_OBJECT; - intern->rescode = MEMCACHED_SUCCESS; + s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); - cas = s_zval_to_uint64(zv_cas); + array_init(return_value); + status = php_memc_result_apply(intern, s_fetch_apply, return_value); - if (memc_user_data->compression) { - MEMC_VAL_SET_FLAG(flags, MEMC_VAL_COMPRESSED); + if (s_memc_status_handle_result_code(intern, status) == FAILURE) { + zval_ptr_dtor(return_value); + RETURN_FROM_GET; } +} +/* }}} */ - /* - * php_memcached uses 16 bits internally to store type, compression and serialization info. - * We use 16 upper bits to store user defined flags. - */ - if (memc_user_data->set_udf_flags >= 0) { - MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) memc_user_data->set_udf_flags)); - } +static +zend_bool s_fetch_all_apply(php_memc_object_t *intern, zend_string *key, zval *value, zval *cas, uint32_t flags, void *in_context) +{ + zval zv; + zval *return_value = (zval *) in_context; - payload = s_zval_to_payload(value, &flags, memc_user_data->serializer, memc_user_data->compression_type); - if (payload == NULL) { - intern->rescode = MEMC_RES_PAYLOAD_FAILURE; - RETURN_FALSE; - } + array_init (&zv); + s_create_result_array(key, value, cas, flags, &zv); - if (by_key) { - status = memcached_cas_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, payload->val, payload->len, expiration, flags, cas); - } else { - status = memcached_cas(intern->memc, key->val, key->len, payload->val, payload->len, expiration, flags, cas); + add_next_index_zval(return_value, &zv); + return 1; +} + +/* {{{ Memcached::fetchAll() + Returns all the results from a previous delayed request */ +PHP_METHOD(Memcached, fetchAll) +{ + const char *res_key = NULL; + size_t res_key_len = 0; + const char *payload = NULL; + size_t payload_len = 0; + uint32_t flags; + uint64_t cas = 0; + zval value, entry, zv_cas; + memcached_result_st result; + memcached_return status = MEMCACHED_SUCCESS; + MEMC_METHOD_INIT_VARS; + + if (zend_parse_parameters_none() == FAILURE) { + return; } - zend_string_release(payload); - if (php_memc_handle_error(intern, status) < 0) { + MEMC_METHOD_FETCH_OBJECT; + s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); + + array_init(return_value); + status = php_memc_result_apply(intern, s_fetch_all_apply, return_value); + + if (s_memc_status_handle_result_code(intern, status) == FAILURE) { + zval_dtor(return_value); RETURN_FALSE; } - - RETURN_TRUE; } /* }}} */ -/* {{{ Memcached::cas(double cas_token, string key, mixed value [, int expiration ]) - Sets the value for the given key, failing if the cas_token doesn't match the one in memcache */ -PHP_METHOD(Memcached, cas) +/* {{{ Memcached::set(string key, mixed value [, int expiration ]) + Sets the value for the given key */ +PHP_METHOD(Memcached, set) { - php_memc_cas_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); + php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_SET, 0); } /* }}} */ -/* {{{ Memcached::casByKey(double cas_token, string server_key, string key, mixed value [, int expiration ]) - Sets the value for the given key on the server identified by the server_key, failing if the cas_token doesn't match the one in memcache */ -PHP_METHOD(Memcached, casByKey) +/* {{{ Memcached::setByKey(string server_key, string key, mixed value [, int expiration ]) + Sets the value for the given key on the server identified by the server key */ +PHP_METHOD(Memcached, setByKey) { - php_memc_cas_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); + php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_SET, 1); } /* }}} */ -/* {{{ Memcached::delete(string key [, int time ]) - Deletes the given key */ -PHP_METHOD(Memcached, delete) +#ifdef HAVE_MEMCACHED_TOUCH +/* {{{ Memcached::touch(string key, [, int expiration ]) + Sets a new expiration for the given key */ +PHP_METHOD(Memcached, touch) { - php_memc_delete_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); + php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_TOUCH, 0); } /* }}} */ -/* {{{ Memcached::deleteMulti(array keys [, int time ]) - Deletes the given keys */ -PHP_METHOD(Memcached, deleteMulti) +/* {{{ Memcached::touchbyKey(string key, [, int expiration ]) + Sets a new expiration for the given key */ +PHP_METHOD(Memcached, touchByKey) { - php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); + php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_TOUCH, 1); } /* }}} */ +#endif -/* {{{ Memcached::deleteByKey(string server_key, string key [, int time ]) - Deletes the given key from the server identified by the server key */ -PHP_METHOD(Memcached, deleteByKey) + +/* {{{ Memcached::setMulti(array items [, int expiration ]) + Sets the keys/values specified in the items array */ +PHP_METHOD(Memcached, setMulti) { - php_memc_delete_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); + php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); } /* }}} */ -/* {{{ Memcached::deleteMultiByKey(array keys [, int time ]) - Deletes the given key from the server identified by the server key */ -PHP_METHOD(Memcached, deleteMultiByKey) +/* {{{ Memcached::setMultiByKey(string server_key, array items [, int expiration ]) + Sets the keys/values specified in the items array on the server identified by the given server key */ +PHP_METHOD(Memcached, setMultiByKey) { - php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); + php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); } /* }}} */ -/* {{{ -- php_memc_delete_impl */ -static void php_memc_delete_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) +/* {{{ -- php_memc_setMulti_impl */ +static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { - zend_string *key, *server_key; + zval *entries; + zend_string *server_key = NULL; time_t expiration = 0; + zval *value; + zend_string *skey, *str_key = NULL; + ulong num_key; + zend_string *payload; + uint32_t flags = 0; + uint32_t retry = 0; memcached_return status; + char tmp_key[MEMCACHED_MAX_KEY]; + int tmp_len = 0; MEMC_METHOD_INIT_VARS; if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|l", &server_key, &key, &expiration) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa|ll", &server_key, + &entries, &expiration) == FAILURE) { return; } } else { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|l", &key, &expiration) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|ll", &entries, &expiration) == FAILURE) { return; } - server_key = key; } MEMC_METHOD_FETCH_OBJECT; - intern->rescode = MEMCACHED_SUCCESS; - - if (by_key) { - status = memcached_delete_by_key(intern->memc, server_key->val, server_key->len, key->val, - key->len, expiration); - } else { - status = memcached_delete(intern->memc, key->val, key->len, expiration); - } + s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); - if (php_memc_handle_error(intern, status) < 0) { - RETURN_FALSE; - } + ZEND_HASH_FOREACH_KEY_VAL (Z_ARRVAL_P(entries), num_key, skey, value) { - RETURN_TRUE; -} -/* }}} */ + zend_string *str_key; -/* {{{ -- php_memc_deleteMulti_impl */ -static void php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) -{ - zval *entries; - zend_string *server_key = NULL; - time_t expiration = 0; - zval *entry; - - memcached_return status; - MEMC_METHOD_INIT_VARS; - - if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa/|l", &server_key, &entries, &expiration) == FAILURE) { - return; - } - } else { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|l", &entries, &expiration) == FAILURE) { - return; + if (skey) { + str_key = skey; } - } - - MEMC_METHOD_FETCH_OBJECT; - intern->rescode = MEMCACHED_SUCCESS; + else { + char tmp_key[64]; - array_init(return_value); - ZEND_HASH_FOREACH_VAL (Z_ARRVAL_P(entries), entry) { - if (Z_TYPE_P(entry) != IS_STRING) { - convert_to_string_ex(entry); + tmp_len = snprintf(tmp_key, sizeof(tmp_key) - 1, "%ld", (long)num_key); + str_key = zend_string_init(tmp_key, tmp_len, 0); } - if (Z_STRLEN_P(entry) == 0) { - continue; + if (!s_memc_write_zval (intern, MEMC_OP_SET, server_key, str_key, value, expiration)) { + php_error_docref(NULL, E_WARNING, "failed to set key %s", str_key->val); } - if (by_key) { - status = memcached_delete_by_key(intern->memc, server_key->val, server_key->len, Z_STRVAL_P(entry), Z_STRLEN_P(entry), expiration); - } else { - status = memcached_delete_by_key(intern->memc, Z_STRVAL_P(entry), Z_STRLEN_P(entry), Z_STRVAL_P(entry), Z_STRLEN_P(entry), expiration); + if (!skey) { + zend_string_release (str_key); } - - if (php_memc_handle_error(intern, status) < 0) { - add_assoc_long(return_value, Z_STRVAL_P(entry), status); - } else { - add_assoc_bool(return_value, Z_STRVAL_P(entry), 1); - } } ZEND_HASH_FOREACH_END(); - return; + RETURN_BOOL(!s_memc_status_has_error(intern)); } /* }}} */ -/* {{{ -- php_memc_incdec_impl */ -static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key, zend_bool incr) +/* {{{ Memcached::add(string key, mixed value [, int expiration ]) + Sets the value for the given key, failing if the key already exists */ +PHP_METHOD(Memcached, add) { - zend_string *key, *server_key = NULL; - long offset = 1; - uint64_t value, initial = 0; - time_t expiry = 0; - memcached_return status; - int n_args = ZEND_NUM_ARGS(); - uint32_t retry = 0; - - MEMC_METHOD_INIT_VARS; - - if (!by_key) { - if (zend_parse_parameters(n_args, "S|lll", &key, &offset, &initial, &expiry) == FAILURE) { - return; - } - } else { - if (zend_parse_parameters(n_args, "SS|lll", &server_key, &key, &offset, &initial, &expiry) == FAILURE) { - return; - } - } - - MEMC_METHOD_FETCH_OBJECT; - intern->rescode = MEMCACHED_SUCCESS; - - if (offset < 0) { - php_error_docref(NULL, E_WARNING, "offset has to be > 0"); - RETURN_FALSE; - } + php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_ADD, 0); +} +/* }}} */ -retry: - if ((!by_key && n_args < 3) || (by_key && n_args < 4)) { - if (by_key) { - if (incr) { - status = memcached_increment_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, (unsigned int)offset, &value); - } else { - status = memcached_decrement_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, (unsigned int)offset, &value); - } - } else { - if (incr) { - status = memcached_increment(intern->memc, key->val, key->len, (unsigned int)offset, &value); - } else { - status = memcached_decrement(intern->memc, key->val, key->len, (unsigned int)offset, &value); - } - } - } else { - if (!memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) { - php_error_docref(NULL, E_WARNING, "Initial value is only supported with binary protocol"); - RETURN_FALSE; - } - if (by_key) { - if (incr) { - status = memcached_increment_with_initial_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, (unsigned int)offset, initial, expiry, &value); - } else { - status = memcached_decrement_with_initial_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, (unsigned int)offset, initial, expiry, &value); - } - } else { - if (incr) { - status = memcached_increment_with_initial(intern->memc, key->val, key->len, (unsigned int)offset, initial, expiry, &value); - } else { - status = memcached_decrement_with_initial(intern->memc, key->val, key->len, (unsigned int)offset, initial, expiry, &value); - } - } - } +/* {{{ Memcached::addByKey(string server_key, string key, mixed value [, int expiration ]) + Sets the value for the given key on the server identified by the sever key, failing if the key already exists */ +PHP_METHOD(Memcached, addByKey) +{ + php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_ADD, 1); +} +/* }}} */ - if (php_memc_handle_error(intern, status) < 0) { - PHP_MEMC_FAILOVER_RETRY - RETURN_FALSE; - } +/* {{{ Memcached::append(string key, mixed value) + Appends the value to existing one for the key */ +PHP_METHOD(Memcached, append) +{ + php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_APPEND, 0); +} +/* }}} */ - RETURN_LONG((long)value); +/* {{{ Memcached::appendByKey(string server_key, string key, mixed value) + Appends the value to existing one for the key on the server identified by the server key */ +PHP_METHOD(Memcached, appendByKey) +{ + php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_APPEND, 1); } /* }}} */ -/* {{{ Memcached::increment(string key [, int delta [, initial_value [, expiry time ] ] ]) - Increments the value for the given key by delta, defaulting to 1 */ -PHP_METHOD(Memcached, increment) +/* {{{ Memcached::prepend(string key, mixed value) + Prepends the value to existing one for the key */ +PHP_METHOD(Memcached, prepend) { - php_memc_incdec_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 1); + php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_PREPEND, 0); } /* }}} */ -/* {{{ Memcached::decrement(string key [, int delta [, initial_value [, expiry time ] ] ]) - Decrements the value for the given key by delta, defaulting to 1 */ -PHP_METHOD(Memcached, decrement) +/* {{{ Memcached::prependByKey(string server_key, string key, mixed value) + Prepends the value to existing one for the key on the server identified by the server key */ +PHP_METHOD(Memcached, prependByKey) { - php_memc_incdec_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0); + php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_PREPEND, 1); } /* }}} */ -/* {{{ Memcached::decrementByKey(string server_key, string key [, int delta [, initial_value [, expiry time ] ] ]) - Decrements by server the value for the given key by delta, defaulting to 1 */ -PHP_METHOD(Memcached, decrementByKey) +/* {{{ Memcached::replace(string key, mixed value [, int expiration ]) + Replaces the value for the given key, failing if the key doesn't exist */ +PHP_METHOD(Memcached, replace) { - php_memc_incdec_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 0); + php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_REPLACE, 0); } /* }}} */ -/* {{{ Memcached::increment(string server_key, string key [, int delta [, initial_value [, expiry time ] ] ]) - Increments by server the value for the given key by delta, defaulting to 1 */ -PHP_METHOD(Memcached, incrementByKey) +/* {{{ Memcached::replaceByKey(string server_key, string key, mixed value [, int expiration ]) + Replaces the value for the given key on the server identified by the server key, failing if the key doesn't exist */ +PHP_METHOD(Memcached, replaceByKey) { - php_memc_incdec_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 1); + php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_REPLACE, 1); } /* }}} */ -/* {{{ Memcached::addServer(string hostname, int port [, int weight ]) - Adds the given memcache server to the list */ -PHP_METHOD(Memcached, addServer) +/* {{{ -- php_memc_store_impl */ +static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool by_key) { - zend_string *host; - long port, weight = 0; + zend_string *key; + zend_string *server_key = NULL; + zend_string *s_value; + zval s_zvalue; + zval *value = NULL; + zend_long expiration = 0; + zend_string *payload = NULL; + uint32_t flags = 0; + uint32_t retry = 0; memcached_return status; MEMC_METHOD_INIT_VARS; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sl|l", &host, &port, &weight) == FAILURE) { - return; + if (by_key) { + if (op == MEMC_OP_APPEND || op == MEMC_OP_PREPEND) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSS", &server_key, &key, &s_value) == FAILURE) { + return; + } + value = &s_zvalue; + ZVAL_STR(value, s_value); + } else if (op == MEMC_OP_TOUCH) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|l", &server_key, &key, &expiration) == FAILURE) { + return; + } + } else { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSz|l", &server_key, &key, &value, &expiration) == FAILURE) { + return; + } + } + } else { + if (op == MEMC_OP_APPEND || op == MEMC_OP_PREPEND) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &key, &s_value) == FAILURE) { + return; + } + value = &s_zvalue; + ZVAL_STR(value, s_value); + } else if (op == MEMC_OP_TOUCH) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|l", &key, &expiration) == FAILURE) { + return; + } + } else { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|l", &key, &value, &expiration) == FAILURE) { + return; + } + } } MEMC_METHOD_FETCH_OBJECT; - intern->rescode = MEMCACHED_SUCCESS; + s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); -#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x01000002 - if (host->val[0] == '/') { /* unix domain socket */ - status = memcached_server_add_unix_socket_with_weight(intern->memc, host->val, weight); - } else if (memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_USE_UDP)) { - status = memcached_server_add_udp_with_weight(intern->memc, host->val, port, weight); - } else { - status = memcached_server_add_with_weight(intern->memc, host->val, port, weight); + if (memc_user_data->compression_enabled) { + /* + * When compression is enabled, we cannot do appends/prepends because that would + * corrupt the compressed values. It is up to the user to fetch the value, + * append/prepend new data, and store it again. + */ + if (op == MEMC_OP_APPEND || op == MEMC_OP_PREPEND) { + php_error_docref(NULL, E_WARNING, "cannot append/prepend with compression turned on"); + RETURN_NULL(); + } } -#else - status = memcached_server_add_with_weight(intern->memc, host->val, port, weight); + + + if (op == MEMC_OP_TOUCH) { +#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x01000016 + if (memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) { + php_error_docref(NULL, E_WARNING, "using touch command with binary protocol is not recommended with libmemcached versions below 1.0.16"); + } #endif + } - if (php_memc_handle_error(intern, status) < 0) { + if (!s_memc_write_zval (intern, op, server_key, key, value, expiration)) { RETURN_FALSE; } - RETURN_TRUE; } /* }}} */ -/* {{{ Memcached::addServers(array servers) - Adds the given memcache servers to the server list */ -PHP_METHOD(Memcached, addServers) +/* {{{ -- php_memc_cas_impl */ +static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { - zval *servers; - zval *entry; - zval *z_host, *z_port, *z_weight = NULL; - uint32_t weight = 0; - HashPosition pos; - int entry_size, i = 0; - memcached_server_st *list = NULL; - memcached_return status; - MEMC_METHOD_INIT_VARS; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/", &servers) == FAILURE) { - return; - } - - MEMC_METHOD_FETCH_OBJECT; - intern->rescode = MEMCACHED_SUCCESS; + zval *zv_cas; + uint64_t cas; + zend_string *key; + zend_string *server_key = NULL; + zval *value; + time_t expiration = 0; + zend_string *payload; + uint32_t flags = 0; + memcached_return status; + MEMC_METHOD_INIT_VARS; - ZEND_HASH_FOREACH_VAL (Z_ARRVAL_P(servers), entry) { - if (Z_TYPE_P(entry) != IS_ARRAY) { - php_error_docref(NULL, E_WARNING, "server list entry #%d is not an array", i+1); - i++; - continue; + if (by_key) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zSSz|ll", &zv_cas, &server_key, &key, + &value, &expiration) == FAILURE) { + return; } + } else { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zSz|ll", &zv_cas, &key, &value, + &expiration) == FAILURE) { + return; + } + } - entry_size = zend_hash_num_elements(Z_ARRVAL_P(entry)); - - if (entry_size > 1) { - zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(entry), &pos); - - /* Check that we have a host */ - if ((z_host = zend_hash_get_current_data_ex(Z_ARRVAL_P(entry), &pos)) == NULL) { - php_error_docref(NULL, E_WARNING, "could not get server host for entry #%d", i+1); - i++; - continue; - } - - /* Check that we have a port */ - if (zend_hash_move_forward_ex(Z_ARRVAL_P(entry), &pos) == FAILURE || - (z_port = zend_hash_get_current_data_ex(Z_ARRVAL_P(entry), &pos)) == NULL) { - php_error_docref(NULL, E_WARNING, "could not get server port for entry #%d", i+1); - i++; - continue; - } - - convert_to_string_ex(z_host); - convert_to_long_ex(z_port); - - weight = 0; - if (entry_size > 2) { - /* Try to get weight */ - if (zend_hash_move_forward_ex(Z_ARRVAL_P(entry), &pos) == FAILURE || - (z_weight = zend_hash_get_current_data_ex(Z_ARRVAL_P(entry), &pos)) == NULL) { - php_error_docref(NULL, E_WARNING, "could not get server weight for entry #%d", i+1); - } + MEMC_METHOD_FETCH_OBJECT; + s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); - convert_to_long_ex(z_weight); - weight = Z_LVAL_P(z_weight); - } + cas = s_zval_to_uint64(zv_cas); - list = memcached_server_list_append_with_weight(list, Z_STRVAL_P(z_host), - Z_LVAL_P(z_port), weight, &status); + payload = s_zval_to_payload(intern, value, &flags); + if (payload == NULL) { + intern->rescode = MEMC_RES_PAYLOAD_FAILURE; + RETURN_FALSE; + } - if (php_memc_handle_error(intern, status) == 0) { - i++; - continue; - } - } - i++; - /* catch-all for all errors */ - php_error_docref(NULL, E_WARNING, "could not add entry #%d to the server list", i+1); - } ZEND_HASH_FOREACH_END(); + if (by_key) { + status = memcached_cas_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, payload->val, payload->len, expiration, flags, cas); + } else { + status = memcached_cas(intern->memc, key->val, key->len, payload->val, payload->len, expiration, flags, cas); + } - status = memcached_server_push(intern->memc, list); - memcached_server_list_free(list); - if (php_memc_handle_error(intern, status) < 0) { + zend_string_release(payload); + if (s_memc_status_handle_result_code(intern, status) == FAILURE) { RETURN_FALSE; } @@ -2076,351 +1997,725 @@ PHP_METHOD(Memcached, addServers) } /* }}} */ -/* {{{ Memcached::getServerList() - Returns the list of the memcache servers in use */ -PHP_METHOD(Memcached, getServerList) +/* {{{ Memcached::cas(double cas_token, string key, mixed value [, int expiration ]) + Sets the value for the given key, failing if the cas_token doesn't match the one in memcache */ +PHP_METHOD(Memcached, cas) { - memcached_server_function callbacks[1]; - MEMC_METHOD_INIT_VARS; - - if (zend_parse_parameters_none() == FAILURE) { - return; - } - - MEMC_METHOD_FETCH_OBJECT; - - callbacks[0] = s_server_cursor_list_servers_cb; - array_init(return_value); - memcached_server_cursor(intern->memc, callbacks, return_value, 1); + php_memc_cas_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); } /* }}} */ -/* {{{ Memcached::getServerByKey(string server_key) - Returns the server identified by the given server key */ -PHP_METHOD(Memcached, getServerByKey) +/* {{{ Memcached::casByKey(double cas_token, string server_key, string key, mixed value [, int expiration ]) + Sets the value for the given key on the server identified by the server_key, failing if the cas_token doesn't match the one in memcache */ +PHP_METHOD(Memcached, casByKey) { - zend_string *server_key; - php_memcached_instance_st server_instance; - memcached_return error; - MEMC_METHOD_INIT_VARS; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &server_key) == FAILURE) { - return; - } - - MEMC_METHOD_FETCH_OBJECT; - intern->rescode = MEMCACHED_SUCCESS; - - server_instance = memcached_server_by_key(intern->memc, server_key->val, server_key->len, &error); - if (server_instance == NULL) { - php_memc_handle_error(intern, error); - RETURN_FALSE; - } - - array_init(return_value); - add_assoc_string(return_value, "host", (char*) memcached_server_name(server_instance)); - add_assoc_long(return_value, "port", memcached_server_port(server_instance)); - add_assoc_long(return_value, "weight", 0); + php_memc_cas_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); } /* }}} */ -/* {{{ Memcached::resetServerList() - Reset the server list in use */ -PHP_METHOD(Memcached, resetServerList) +/* {{{ Memcached::delete(string key [, int time ]) + Deletes the given key */ +PHP_METHOD(Memcached, delete) { - MEMC_METHOD_INIT_VARS; - - if (zend_parse_parameters_none() == FAILURE) { - return; - } - - MEMC_METHOD_FETCH_OBJECT; - - memcached_servers_reset(intern->memc); - RETURN_TRUE; + php_memc_delete_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); } /* }}} */ -/* {{{ Memcached::quit() - Close any open connections */ -PHP_METHOD(Memcached, quit) +/* {{{ Memcached::deleteMulti(array keys [, int time ]) + Deletes the given keys */ +PHP_METHOD(Memcached, deleteMulti) { - MEMC_METHOD_INIT_VARS; - - if (zend_parse_parameters_none() == FAILURE) { - return; - } - - MEMC_METHOD_FETCH_OBJECT; - - memcached_quit(intern->memc); - RETURN_TRUE; + php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); } /* }}} */ -/* {{{ Memcached::flushBuffers() - Flush and senf buffered commands */ -PHP_METHOD(Memcached, flushBuffers) +/* {{{ Memcached::deleteByKey(string server_key, string key [, int time ]) + Deletes the given key from the server identified by the server key */ +PHP_METHOD(Memcached, deleteByKey) { - MEMC_METHOD_INIT_VARS; - - if (zend_parse_parameters_none() == FAILURE) { - return; - } - - MEMC_METHOD_FETCH_OBJECT; - RETURN_BOOL(memcached_flush_buffers(intern->memc) == MEMCACHED_SUCCESS); + php_memc_delete_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); } /* }}} */ -#ifdef HAVE_LIBMEMCACHED_CHECK_CONFIGURATION -/* {{{ Memcached::getLastErrorMessage() - Returns the last error message that occurred */ -PHP_METHOD(Memcached, getLastErrorMessage) +/* {{{ Memcached::deleteMultiByKey(array keys [, int time ]) + Deletes the given key from the server identified by the server key */ +PHP_METHOD(Memcached, deleteMultiByKey) { - MEMC_METHOD_INIT_VARS; - - if (zend_parse_parameters_none() == FAILURE) { - return; - } - - MEMC_METHOD_FETCH_OBJECT; - - RETURN_STRING(memcached_last_error_message(intern->memc)); + php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); } /* }}} */ -/* {{{ Memcached::getLastErrorCode() - Returns the last error code that occurred */ -PHP_METHOD(Memcached, getLastErrorCode) +/* {{{ -- php_memc_delete_impl */ +static void php_memc_delete_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { + zend_string *key, *server_key; + time_t expiration = 0; + memcached_return status; MEMC_METHOD_INIT_VARS; - if (zend_parse_parameters_none() == FAILURE) { - return; + if (by_key) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|l", &server_key, &key, &expiration) == FAILURE) { + return; + } + } else { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|l", &key, &expiration) == FAILURE) { + return; + } + server_key = key; } MEMC_METHOD_FETCH_OBJECT; + s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); - RETURN_LONG(memcached_last_error(intern->memc)); + if (by_key) { + status = memcached_delete_by_key(intern->memc, server_key->val, server_key->len, key->val, + key->len, expiration); + } else { + status = memcached_delete(intern->memc, key->val, key->len, expiration); + } + + if (s_memc_status_handle_result_code(intern, status) == FAILURE) { + RETURN_FALSE; + } + + RETURN_TRUE; } /* }}} */ -/* {{{ Memcached::getLastErrorErrno() - Returns the last error errno that occurred */ -PHP_METHOD(Memcached, getLastErrorErrno) +/* {{{ -- php_memc_deleteMulti_impl */ +static void php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { + zval *entries; + zend_string *server_key = NULL; + time_t expiration = 0; + zval *entry; + + memcached_return status; MEMC_METHOD_INIT_VARS; - if (zend_parse_parameters_none() == FAILURE) { - return; + if (by_key) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa/|l", &server_key, &entries, &expiration) == FAILURE) { + return; + } + } else { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|l", &entries, &expiration) == FAILURE) { + return; + } } MEMC_METHOD_FETCH_OBJECT; - - RETURN_LONG(memcached_last_error_errno(intern->memc)); -} -/* }}} */ -#endif - -/* {{{ Memcached::getLastDisconnectedServer() - Returns the last disconnected server - Was added in 0.34 according to libmemcached's Changelog */ -PHP_METHOD(Memcached, getLastDisconnectedServer) -{ - php_memcached_instance_st server_instance; - MEMC_METHOD_INIT_VARS; - - if (zend_parse_parameters_none() == FAILURE) { - return; - } - - MEMC_METHOD_FETCH_OBJECT; - - server_instance = memcached_server_get_last_disconnect(intern->memc); - if (server_instance == NULL) { - RETURN_FALSE; - } + s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); array_init(return_value); - add_assoc_string(return_value, "host", (char*) memcached_server_name(server_instance)); - add_assoc_long(return_value, "port", memcached_server_port(server_instance)); -} -/* }}} */ - -#include - -static -zend_bool s_long_value(const char *str, zend_long *value) -{ - char *end = (char *) str; - - errno = 0; - *value = strtol(str, &end, 10); - - if (errno || str == end || *end != '\0') { - return 0; - } - return 1; -} - -static -zend_bool s_double_value(const char *str, double *value) -{ - char *end = (char *) str; - - errno = 0; - *value = strtod(str, &end); - - if (errno || str == end || *end != '\0') { - return 0; - } - return 1; -} - -static -memcached_return s_stat_execute_cb (php_memcached_instance_st instance, const char *key, size_t key_length, const char *value, size_t value_length, void *context) -{ - char *server_key; - size_t server_key_len; - zend_long long_val; - double d_val; - char *buffer; - - zval *return_value = (zval *) context; - zval *server_values; + ZEND_HASH_FOREACH_VAL (Z_ARRVAL_P(entries), entry) { + if (Z_TYPE_P(entry) != IS_STRING) { + convert_to_string_ex(entry); + } - server_key_len = spprintf (&server_key, 0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance)); - server_values = zend_hash_str_find(Z_ARRVAL_P(return_value), server_key, server_key_len); + if (Z_STRLEN_P(entry) == 0) { + continue; + } - if (!server_values) { - zval zv; - array_init(&zv); + if (by_key) { + status = memcached_delete_by_key(intern->memc, server_key->val, server_key->len, Z_STRVAL_P(entry), Z_STRLEN_P(entry), expiration); + } else { + status = memcached_delete_by_key(intern->memc, Z_STRVAL_P(entry), Z_STRLEN_P(entry), Z_STRVAL_P(entry), Z_STRLEN_P(entry), expiration); + } - server_values = &zv; - add_assoc_zval_ex(return_value, server_key, server_key_len, server_values); - } - spprintf (&buffer, 0, "%.*s", value_length, value); + if (s_memc_status_handle_result_code(intern, status) == FAILURE) { + add_assoc_long(return_value, Z_STRVAL_P(entry), status); + } else { + add_assoc_bool(return_value, Z_STRVAL_P(entry), 1); + } + } ZEND_HASH_FOREACH_END(); - /* Check type */ - if (s_long_value (buffer, &long_val)) { - add_assoc_long(server_values, key, long_val); - } - else if (s_double_value (buffer, &d_val)) { - add_assoc_double(server_values, key, d_val); - } - else { - add_assoc_stringl_ex(server_values, key, key_length, value, value_length); - } - efree (buffer); - efree (server_key); - return MEMCACHED_SUCCESS; + return; } +/* }}} */ -/* {{{ Memcached::getStats() - Returns statistics for the memcache servers */ -PHP_METHOD(Memcached, getStats) +/* {{{ -- php_memc_incdec_impl */ +static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key, zend_bool incr) { + zend_string *key, *server_key = NULL; + long offset = 1; + uint64_t value = UINT64_MAX, initial = 0; + time_t expiry = 0; memcached_return status; + int n_args = ZEND_NUM_ARGS(); + MEMC_METHOD_INIT_VARS; - if (zend_parse_parameters_none() == FAILURE) { - return; + if (!by_key) { + if (zend_parse_parameters(n_args, "S|lll", &key, &offset, &initial, &expiry) == FAILURE) { + return; + } + } else { + if (zend_parse_parameters(n_args, "SS|lll", &server_key, &key, &offset, &initial, &expiry) == FAILURE) { + return; + } } MEMC_METHOD_FETCH_OBJECT; + s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); - array_init(return_value); - status = memcached_stat_execute(intern->memc, NULL, s_stat_execute_cb, return_value); - if (php_memc_handle_error(intern, status) < 0) { - zval_ptr_dtor(return_value); + if (offset < 0) { + php_error_docref(NULL, E_WARNING, "offset has to be > 0"); RETURN_FALSE; } -} -/* }}} */ -/* {{{ Memcached::getVersion() - Returns the version of each memcached server in the pool */ -PHP_METHOD(Memcached, getVersion) -{ - memcached_return rc; - memcached_server_function callbacks[1]; - MEMC_METHOD_INIT_VARS; + if ((!by_key && n_args < 3) || (by_key && n_args < 4)) { + if (by_key) { + if (incr) { + status = memcached_increment_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, (unsigned int)offset, &value); + } else { + status = memcached_decrement_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, (unsigned int)offset, &value); + } + } else { + if (incr) { + status = memcached_increment(intern->memc, key->val, key->len, (unsigned int)offset, &value); + } else { + status = memcached_decrement(intern->memc, key->val, key->len, (unsigned int)offset, &value); + } + } - if (zend_parse_parameters_none() == FAILURE) { - return; - } + } else { + zend_long retries = memc_user_data->store_retry_count; - MEMC_METHOD_FETCH_OBJECT; +retry_inc_dec: + if (!memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) { + php_error_docref(NULL, E_WARNING, "Initial value is only supported with binary protocol"); + RETURN_FALSE; + } + if (by_key) { + if (incr) { + status = memcached_increment_with_initial_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, (unsigned int)offset, initial, expiry, &value); + } else { + status = memcached_decrement_with_initial_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, (unsigned int)offset, initial, expiry, &value); + } + } else { + if (incr) { + status = memcached_increment_with_initial(intern->memc, key->val, key->len, (unsigned int)offset, initial, expiry, &value); + } else { + status = memcached_decrement_with_initial(intern->memc, key->val, key->len, (unsigned int)offset, initial, expiry, &value); + } + } + if (s_should_retry_write(intern, status) && retries-- > 0) { + goto retry_inc_dec; + } + } - rc = memcached_version(intern->memc); - if (php_memc_handle_error(intern, rc) < 0) { + if (value == UINT64_MAX) { RETURN_FALSE; } - callbacks[0] = s_server_cursor_version_cb; - - array_init(return_value); - rc = memcached_server_cursor(intern->memc, callbacks, return_value, 1); - if (php_memc_handle_error(intern, rc) < 0) { - zval_dtor(return_value); + if (s_memc_status_handle_result_code(intern, status) == FAILURE) { RETURN_FALSE; } + + RETURN_LONG((long)value); } /* }}} */ -/* {{{ Memcached::getAllKeys() - Returns the keys stored on all the servers */ -static -memcached_return s_dump_keys_cb(const memcached_st *ptr, const char *key, size_t key_length, void *in_context) +/* {{{ Memcached::increment(string key [, int delta [, initial_value [, expiry time ] ] ]) + Increments the value for the given key by delta, defaulting to 1 */ +PHP_METHOD(Memcached, increment) { - zval *return_value = (zval*) in_context; - add_next_index_stringl(return_value, key, key_length); - - return MEMCACHED_SUCCESS; + php_memc_incdec_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 1); } +/* }}} */ -PHP_METHOD(Memcached, getAllKeys) +/* {{{ Memcached::decrement(string key [, int delta [, initial_value [, expiry time ] ] ]) + Decrements the value for the given key by delta, defaulting to 1 */ +PHP_METHOD(Memcached, decrement) { - memcached_return rc; - memcached_dump_func callback[1]; - MEMC_METHOD_INIT_VARS; - - if (zend_parse_parameters_none() == FAILURE) { - return; - } - - callback[0] = s_dump_keys_cb; - MEMC_METHOD_FETCH_OBJECT; + php_memc_incdec_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0); +} +/* }}} */ - array_init(return_value); +/* {{{ Memcached::decrementByKey(string server_key, string key [, int delta [, initial_value [, expiry time ] ] ]) + Decrements by server the value for the given key by delta, defaulting to 1 */ +PHP_METHOD(Memcached, decrementByKey) +{ + php_memc_incdec_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 0); +} +/* }}} */ - rc = memcached_dump(intern->memc, callback, return_value, 1); - if (php_memc_handle_error(intern, rc) < 0) { - zval_dtor(return_value); - RETURN_FALSE; - } +/* {{{ Memcached::increment(string server_key, string key [, int delta [, initial_value [, expiry time ] ] ]) + Increments by server the value for the given key by delta, defaulting to 1 */ +PHP_METHOD(Memcached, incrementByKey) +{ + php_memc_incdec_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 1); } /* }}} */ -/* {{{ Memcached::flush([ int delay ]) - Flushes the data on all the servers */ -static PHP_METHOD(Memcached, flush) +/* {{{ Memcached::addServer(string hostname, int port [, int weight ]) + Adds the given memcache server to the list */ +PHP_METHOD(Memcached, addServer) { - time_t delay = 0; + zend_string *host; + long port, weight = 0; memcached_return status; MEMC_METHOD_INIT_VARS; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &delay) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sl|l", &host, &port, &weight) == FAILURE) { return; } MEMC_METHOD_FETCH_OBJECT; intern->rescode = MEMCACHED_SUCCESS; - status = memcached_flush(intern->memc, delay); - if (php_memc_handle_error(intern, status) < 0) { +#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x01000002 + if (host->val[0] == '/') { /* unix domain socket */ + status = memcached_server_add_unix_socket_with_weight(intern->memc, host->val, weight); + } else if (memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_USE_UDP)) { + status = memcached_server_add_udp_with_weight(intern->memc, host->val, port, weight); + } else { + status = memcached_server_add_with_weight(intern->memc, host->val, port, weight); + } +#else + status = memcached_server_add_with_weight(intern->memc, host->val, port, weight); +#endif + + if (s_memc_status_handle_result_code(intern, status) == FAILURE) { + RETURN_FALSE; + } + + RETURN_TRUE; +} +/* }}} */ + +/* {{{ Memcached::addServers(array servers) + Adds the given memcache servers to the server list */ +PHP_METHOD(Memcached, addServers) +{ + zval *servers; + zval *entry; + zval *z_host, *z_port, *z_weight = NULL; + uint32_t weight = 0; + HashPosition pos; + int entry_size, i = 0; + memcached_server_st *list = NULL; + memcached_return status; + MEMC_METHOD_INIT_VARS; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/", &servers) == FAILURE) { + return; + } + + MEMC_METHOD_FETCH_OBJECT; + s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); + + ZEND_HASH_FOREACH_VAL (Z_ARRVAL_P(servers), entry) { + if (Z_TYPE_P(entry) != IS_ARRAY) { + php_error_docref(NULL, E_WARNING, "server list entry #%d is not an array", i+1); + i++; + continue; + } + + entry_size = zend_hash_num_elements(Z_ARRVAL_P(entry)); + + if (entry_size > 1) { + zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(entry), &pos); + + /* Check that we have a host */ + if ((z_host = zend_hash_get_current_data_ex(Z_ARRVAL_P(entry), &pos)) == NULL) { + php_error_docref(NULL, E_WARNING, "could not get server host for entry #%d", i+1); + i++; + continue; + } + + /* Check that we have a port */ + if (zend_hash_move_forward_ex(Z_ARRVAL_P(entry), &pos) == FAILURE || + (z_port = zend_hash_get_current_data_ex(Z_ARRVAL_P(entry), &pos)) == NULL) { + php_error_docref(NULL, E_WARNING, "could not get server port for entry #%d", i+1); + i++; + continue; + } + + convert_to_string_ex(z_host); + convert_to_long_ex(z_port); + + weight = 0; + if (entry_size > 2) { + /* Try to get weight */ + if (zend_hash_move_forward_ex(Z_ARRVAL_P(entry), &pos) == FAILURE || + (z_weight = zend_hash_get_current_data_ex(Z_ARRVAL_P(entry), &pos)) == NULL) { + php_error_docref(NULL, E_WARNING, "could not get server weight for entry #%d", i+1); + } + + convert_to_long_ex(z_weight); + weight = Z_LVAL_P(z_weight); + } + + list = memcached_server_list_append_with_weight(list, Z_STRVAL_P(z_host), + Z_LVAL_P(z_port), weight, &status); + + if (s_memc_status_handle_result_code(intern, status) == SUCCESS) { + i++; + continue; + } + } + i++; + /* catch-all for all errors */ + php_error_docref(NULL, E_WARNING, "could not add entry #%d to the server list", i+1); + } ZEND_HASH_FOREACH_END(); + + status = memcached_server_push(intern->memc, list); + memcached_server_list_free(list); + if (s_memc_status_handle_result_code(intern, status) == FAILURE) { + RETURN_FALSE; + } + + RETURN_TRUE; +} +/* }}} */ + +/* {{{ Memcached::getServerList() + Returns the list of the memcache servers in use */ +PHP_METHOD(Memcached, getServerList) +{ + memcached_server_function callbacks[1]; + MEMC_METHOD_INIT_VARS; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + MEMC_METHOD_FETCH_OBJECT; + + callbacks[0] = s_server_cursor_list_servers_cb; + array_init(return_value); + memcached_server_cursor(intern->memc, callbacks, return_value, 1); +} +/* }}} */ + +/* {{{ Memcached::getServerByKey(string server_key) + Returns the server identified by the given server key */ +PHP_METHOD(Memcached, getServerByKey) +{ + zend_string *server_key; + php_memcached_instance_st server_instance; + memcached_return error; + MEMC_METHOD_INIT_VARS; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &server_key) == FAILURE) { + return; + } + + MEMC_METHOD_FETCH_OBJECT; + s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); + + server_instance = memcached_server_by_key(intern->memc, server_key->val, server_key->len, &error); + if (server_instance == NULL) { + s_memc_status_handle_result_code(intern, error); + RETURN_FALSE; + } + + array_init(return_value); + add_assoc_string(return_value, "host", (char*) memcached_server_name(server_instance)); + add_assoc_long(return_value, "port", memcached_server_port(server_instance)); + add_assoc_long(return_value, "weight", 0); +} +/* }}} */ + +/* {{{ Memcached::resetServerList() + Reset the server list in use */ +PHP_METHOD(Memcached, resetServerList) +{ + MEMC_METHOD_INIT_VARS; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + MEMC_METHOD_FETCH_OBJECT; + + memcached_servers_reset(intern->memc); + RETURN_TRUE; +} +/* }}} */ + +/* {{{ Memcached::quit() + Close any open connections */ +PHP_METHOD(Memcached, quit) +{ + MEMC_METHOD_INIT_VARS; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + MEMC_METHOD_FETCH_OBJECT; + + memcached_quit(intern->memc); + RETURN_TRUE; +} +/* }}} */ + +/* {{{ Memcached::flushBuffers() + Flush and senf buffered commands */ +PHP_METHOD(Memcached, flushBuffers) +{ + MEMC_METHOD_INIT_VARS; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + MEMC_METHOD_FETCH_OBJECT; + RETURN_BOOL(memcached_flush_buffers(intern->memc) == MEMCACHED_SUCCESS); +} +/* }}} */ + +#ifdef HAVE_LIBMEMCACHED_CHECK_CONFIGURATION +/* {{{ Memcached::getLastErrorMessage() + Returns the last error message that occurred */ +PHP_METHOD(Memcached, getLastErrorMessage) +{ + MEMC_METHOD_INIT_VARS; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + MEMC_METHOD_FETCH_OBJECT; + + RETURN_STRING(memcached_last_error_message(intern->memc)); +} +/* }}} */ + +/* {{{ Memcached::getLastErrorCode() + Returns the last error code that occurred */ +PHP_METHOD(Memcached, getLastErrorCode) +{ + MEMC_METHOD_INIT_VARS; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + MEMC_METHOD_FETCH_OBJECT; + + RETURN_LONG(memcached_last_error(intern->memc)); +} +/* }}} */ + +/* {{{ Memcached::getLastErrorErrno() + Returns the last error errno that occurred */ +PHP_METHOD(Memcached, getLastErrorErrno) +{ + MEMC_METHOD_INIT_VARS; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + MEMC_METHOD_FETCH_OBJECT; + + RETURN_LONG(memcached_last_error_errno(intern->memc)); +} +/* }}} */ +#endif + +/* {{{ Memcached::getLastDisconnectedServer() + Returns the last disconnected server + Was added in 0.34 according to libmemcached's Changelog */ +PHP_METHOD(Memcached, getLastDisconnectedServer) +{ + php_memcached_instance_st server_instance; + MEMC_METHOD_INIT_VARS; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + MEMC_METHOD_FETCH_OBJECT; + + server_instance = memcached_server_get_last_disconnect(intern->memc); + if (server_instance == NULL) { + RETURN_FALSE; + } + + array_init(return_value); + add_assoc_string(return_value, "host", (char*) memcached_server_name(server_instance)); + add_assoc_long(return_value, "port", memcached_server_port(server_instance)); +} +/* }}} */ + + + +static +zend_bool s_long_value(const char *str, zend_long *value) +{ + char *end = (char *) str; + + errno = 0; + *value = strtol(str, &end, 10); + + if (errno || str == end || *end != '\0') { + return 0; + } + return 1; +} + +static +zend_bool s_double_value(const char *str, double *value) +{ + char *end = (char *) str; + + errno = 0; + *value = strtod(str, &end); + + if (errno || str == end || *end != '\0') { + return 0; + } + return 1; +} + +static +memcached_return s_stat_execute_cb (php_memcached_instance_st instance, const char *key, size_t key_length, const char *value, size_t value_length, void *context) +{ + char *server_key; + size_t server_key_len; + zend_long long_val; + double d_val; + char *buffer; + + zval *return_value = (zval *) context; + zval *server_values; + + server_key_len = spprintf (&server_key, 0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance)); + server_values = zend_hash_str_find(Z_ARRVAL_P(return_value), server_key, server_key_len); + + if (!server_values) { + zval zv; + array_init(&zv); + + server_values = &zv; + add_assoc_zval_ex(return_value, server_key, server_key_len, server_values); + } + + spprintf (&buffer, 0, "%.*s", value_length, value); + + /* Check type */ + if (s_long_value (buffer, &long_val)) { + add_assoc_long(server_values, key, long_val); + } + else if (s_double_value (buffer, &d_val)) { + add_assoc_double(server_values, key, d_val); + } + else { + add_assoc_stringl_ex(server_values, key, key_length, value, value_length); + } + efree (buffer); + efree (server_key); + return MEMCACHED_SUCCESS; +} + +/* {{{ Memcached::getStats() + Returns statistics for the memcache servers */ +PHP_METHOD(Memcached, getStats) +{ + memcached_return status; + MEMC_METHOD_INIT_VARS; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + MEMC_METHOD_FETCH_OBJECT; + + array_init(return_value); + status = memcached_stat_execute(intern->memc, NULL, s_stat_execute_cb, return_value); + if (s_memc_status_handle_result_code(intern, status) == FAILURE) { + zval_ptr_dtor(return_value); + RETURN_FALSE; + } +} +/* }}} */ + +/* {{{ Memcached::getVersion() + Returns the version of each memcached server in the pool */ +PHP_METHOD(Memcached, getVersion) +{ + memcached_return status; + memcached_server_function callbacks[1]; + MEMC_METHOD_INIT_VARS; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + MEMC_METHOD_FETCH_OBJECT; + + status = memcached_version(intern->memc); + if (s_memc_status_handle_result_code(intern, status) == FAILURE) { + RETURN_FALSE; + } + + callbacks[0] = s_server_cursor_version_cb; + + array_init(return_value); + status = memcached_server_cursor(intern->memc, callbacks, return_value, 1); + if (s_memc_status_handle_result_code(intern, status) == FAILURE) { + zval_dtor(return_value); + RETURN_FALSE; + } +} +/* }}} */ + +/* {{{ Memcached::getAllKeys() + Returns the keys stored on all the servers */ +static +memcached_return s_dump_keys_cb(const memcached_st *ptr, const char *key, size_t key_length, void *in_context) +{ + zval *return_value = (zval*) in_context; + add_next_index_stringl(return_value, key, key_length); + + return MEMCACHED_SUCCESS; +} + +PHP_METHOD(Memcached, getAllKeys) +{ + memcached_return rc; + memcached_dump_func callback[1]; + MEMC_METHOD_INIT_VARS; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + callback[0] = s_dump_keys_cb; + MEMC_METHOD_FETCH_OBJECT; + + array_init(return_value); + + rc = memcached_dump(intern->memc, callback, return_value, 1); + if (s_memc_status_handle_result_code(intern, rc) == FAILURE) { + zval_dtor(return_value); + RETURN_FALSE; + } +} +/* }}} */ + +/* {{{ Memcached::flush([ int delay ]) + Flushes the data on all the servers */ +static PHP_METHOD(Memcached, flush) +{ + time_t delay = 0; + memcached_return status; + MEMC_METHOD_INIT_VARS; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &delay) == FAILURE) { + return; + } + + MEMC_METHOD_FETCH_OBJECT; + intern->rescode = MEMCACHED_SUCCESS; + + status = memcached_flush(intern->memc, delay); + if (s_memc_status_handle_result_code(intern, status) == FAILURE) { RETURN_FALSE; } @@ -2448,7 +2743,7 @@ static PHP_METHOD(Memcached, getOption) RETURN_LONG(memc_user_data->compression_type); case MEMC_OPT_COMPRESSION: - RETURN_BOOL(memc_user_data->compression); + RETURN_BOOL(memc_user_data->compression_enabled); case MEMC_OPT_PREFIX_KEY: { @@ -2507,7 +2802,7 @@ int php_memc_set_option(php_memc_object_t *intern, long option, zval *value) switch (option) { case MEMC_OPT_COMPRESSION: convert_to_long(value); - memc_user_data->compression = Z_LVAL_P(value) ? 1 : 0; + memc_user_data->compression_enabled = Z_LVAL_P(value) ? 1 : 0; break; case MEMC_OPT_COMPRESSION_TYPE: @@ -2557,7 +2852,7 @@ int php_memc_set_option(php_memc_object_t *intern, long option, zval *value) convert_to_long(value); rc = memcached_behavior_set(intern->memc, flag, (uint64_t) Z_LVAL_P(value)); - if (php_memc_handle_error(intern, rc) < 0) { + if (s_memc_status_handle_result_code(intern, rc) == FAILURE) { php_error_docref(NULL, E_WARNING, "error setting memcached option: %s", memcached_strerror (intern->memc, rc)); return 0; } @@ -2652,7 +2947,7 @@ int php_memc_set_option(php_memc_object_t *intern, long option, zval *value) } } - if (php_memc_handle_error(intern, rc) < 0) { + if (s_memc_status_handle_result_code(intern, rc) == FAILURE) { php_error_docref(NULL, E_WARNING, "error setting memcached option: %s", memcached_strerror (intern->memc, rc)); return 0; } @@ -2751,7 +3046,7 @@ PHP_METHOD(Memcached, setBucket) rc = memcached_bucket_set (intern->memc, server_map, forward_map, (uint32_t) server_map_len, replicas); - if (php_memc_handle_error(intern, rc) < 0) { + if (s_memc_status_handle_result_code(intern, rc) == FAILURE) { retval = 0;; } @@ -2790,546 +3085,286 @@ static PHP_METHOD(Memcached, setOptions) zval copy; ZVAL_DUP(©, value); - if (!php_memc_set_option(intern, (long) key_index, ©)) { - ok = 0; - } - - zval_dtor(©); - } - } ZEND_HASH_FOREACH_END(); - - RETURN_BOOL(ok); -} -/* }}} */ - -/* {{{ Memcached::setOption(int option, mixed value) - Sets the value for the given option constant */ -static PHP_METHOD(Memcached, setOption) -{ - long option; - zval *value; - MEMC_METHOD_INIT_VARS; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz/", &option, &value) == FAILURE) { - return; - } - - MEMC_METHOD_FETCH_OBJECT; - - RETURN_BOOL(php_memc_set_option(intern, option, value)); -} -/* }}} */ - -#ifdef HAVE_MEMCACHED_SASL -/* {{{ Memcached::setSaslAuthData(string user, string pass) - Sets sasl credentials */ -static PHP_METHOD(Memcached, setSaslAuthData) -{ - MEMC_METHOD_INIT_VARS; - memcached_return status; - zend_string *user, *pass; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &user, &pass) == FAILURE) { - return; - } - - if (!php_memc_init_sasl_if_needed()) { - RETURN_FALSE; - } - - MEMC_METHOD_FETCH_OBJECT; - - if (!memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) { - php_error_docref(NULL, E_WARNING, "SASL is only supported with binary protocol"); - RETURN_FALSE; - } - memc_user_data->has_sasl_data = 1; - status = memcached_set_sasl_auth_data(intern->memc, user->val, pass->val); - - if (php_memc_handle_error(intern, status) < 0) { - RETURN_FALSE; - } - RETURN_TRUE; -} -/* }}} */ -#endif /* HAVE_MEMCACHED_SASL */ - -/* {{{ Memcached::getResultCode() - Returns the result code from the last operation */ -static PHP_METHOD(Memcached, getResultCode) -{ - MEMC_METHOD_INIT_VARS; - - if (zend_parse_parameters_none() == FAILURE) { - return; - } - - MEMC_METHOD_FETCH_OBJECT; - - RETURN_LONG(intern->rescode); -} -/* }}} */ - -/* {{{ Memcached::getResultMessage() - Returns the result message from the last operation */ -static PHP_METHOD(Memcached, getResultMessage) -{ - MEMC_METHOD_INIT_VARS; - - if (zend_parse_parameters_none() == FAILURE) { - return; - } - - MEMC_METHOD_FETCH_OBJECT; - - switch (intern->rescode) { - case MEMC_RES_PAYLOAD_FAILURE: - RETURN_STRING("PAYLOAD FAILURE"); - break; - - case MEMCACHED_ERRNO: - case MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE: - case MEMCACHED_UNKNOWN_READ_FAILURE: - if (intern->memc_errno) { - zend_string *str = strpprintf(0, "%s: %s", - memcached_strerror(intern->memc, (memcached_return)intern->rescode), strerror(intern->memc_errno)); - RETURN_STR(str); - } - /* Fall through */ - default: - RETURN_STRING(memcached_strerror(intern->memc, (memcached_return)intern->rescode)); - break; - } - -} -/* }}} */ - -/* {{{ Memcached::isPersistent() - Returns the true if instance uses a persistent connection */ -static PHP_METHOD(Memcached, isPersistent) -{ - MEMC_METHOD_INIT_VARS; - - if (zend_parse_parameters_none() == FAILURE) { - return; - } - - MEMC_METHOD_FETCH_OBJECT; - - RETURN_BOOL(memc_user_data->is_persistent); -} -/* }}} */ - -/* {{{ Memcached::isPristine() - Returns the true if instance is recently created */ -static PHP_METHOD(Memcached, isPristine) -{ - MEMC_METHOD_INIT_VARS; - - if (zend_parse_parameters_none() == FAILURE) { - return; - } - - MEMC_METHOD_FETCH_OBJECT; - - RETURN_BOOL(intern->is_pristine); -} -/* }}} */ - -/**************************************** - Internal support code -****************************************/ - -/* {{{ constructor/destructor */ -static -void php_memc_destroy(memcached_st *memc, php_memc_user_data_t *memc_user_data) -{ -#if HAVE_MEMCACHED_SASL - if (memc_user_data->has_sasl_data) { - memcached_destroy_sasl_auth_data(memc); - } -#endif - - memcached_set_memory_allocators(memc, NULL, NULL, NULL, NULL, NULL); - memcached_free(memc); - pefree(memc_user_data, memc_user_data->is_persistent); -} - -static -void php_memc_object_free_storage(zend_object *object) -{ - php_memc_object_t *intern = php_memc_fetch_object(object); - - if (intern->memc) { - php_memc_user_data_t *memc_user_data = memcached_get_user_data(intern->memc); - - if (!memc_user_data->is_persistent) { - php_memc_destroy(intern->memc, memc_user_data); - } - } - - intern->memc = NULL; - zend_object_std_dtor(&intern->zo); -} - -static -zend_object *php_memc_object_new(zend_class_entry *ce) -{ - php_memc_object_t *intern = ecalloc(1, sizeof(php_memc_object_t) + zend_object_properties_size(ce)); - - zend_object_std_init(&intern->zo, ce); - object_properties_init(&intern->zo, ce); - - intern->zo.handlers = &memcached_object_handlers; - return &intern->zo; -} - -#ifdef HAVE_MEMCACHED_PROTOCOL -static -void php_memc_server_free_storage(php_memc_server_t *intern) -{ - zend_object_std_dtor(&intern->zo); - efree (intern); -} - -zend_object_value php_memc_server_new(zend_class_entry *ce) -{ - zend_object_value retval; - php_memc_server_t *intern; - zval *tmp; - - intern = ecalloc(1, sizeof(php_memc_server_t)); - zend_object_std_init(&intern->zo, ce); - object_properties_init(&intern->zo, ce); - - intern->handler = php_memc_proto_handler_new (); - - retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)php_memc_server_free_storage, NULL); - retval.handlers = &memcached_server_object_handlers; - - return retval; -} -#endif - -ZEND_RSRC_DTOR_FUNC(php_memc_dtor) -{ - if (res->ptr) { - memcached_st *memc = (memcached_st *) res->ptr; - php_memc_destroy(memc, memcached_get_user_data(memc)); - res->ptr = NULL; - } -} - -/* }}} */ - -/* {{{ internal API functions */ -static -memcached_return s_server_cursor_list_servers_cb(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context) -{ - zval array; - zval *return_value = (zval *) in_context; - - array_init(&array); - add_assoc_string(&array, "host", memcached_server_name(instance)); - add_assoc_long(&array, "port", memcached_server_port(instance)); - add_assoc_string(&array, "type", memcached_server_type(instance)); - /* - * API does not allow to get at this field. - add_assoc_long(array, "weight", instance->weight); - */ + if (!php_memc_set_option(intern, (long) key_index, ©)) { + ok = 0; + } - add_next_index_zval(return_value, &array); - return MEMCACHED_SUCCESS; + zval_dtor(©); + } + } ZEND_HASH_FOREACH_END(); + + RETURN_BOOL(ok); } +/* }}} */ -static -memcached_return s_server_cursor_version_cb(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context) +/* {{{ Memcached::setOption(int option, mixed value) + Sets the value for the given option constant */ +static PHP_METHOD(Memcached, setOption) { - char *address, *version; - size_t address_len, version_len; - - zval *return_value = (zval *) in_context; + long option; + zval *value; + MEMC_METHOD_INIT_VARS; -#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x01000009 - version_len = spprintf(&version, sizeof(version), "%d.%d.%d", - memcached_server_major_version(instance), - memcached_server_minor_version(instance), - memcached_server_micro_version(instance)); -#else - version_len = spprintf(&version, sizeof(version) - 1, "%d.%d.%d", - instance->major_version, - instance->minor_version, - instance->micro_version); -#endif + if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz/", &option, &value) == FAILURE) { + return; + } - address_len = spprintf(&address, 0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance) - 1); - add_assoc_stringl_ex(return_value, address, address_len, version, version_len); + MEMC_METHOD_FETCH_OBJECT; - efree(address); - efree(version); - return MEMCACHED_SUCCESS; + RETURN_BOOL(php_memc_set_option(intern, option, value)); } +/* }}} */ -static int php_memc_handle_error(php_memc_object_t *intern, memcached_return status) +#ifdef HAVE_MEMCACHED_SASL +/* {{{ Memcached::setSaslAuthData(string user, string pass) + Sets sasl credentials */ +static PHP_METHOD(Memcached, setSaslAuthData) { - int result = 0; + MEMC_METHOD_INIT_VARS; + memcached_return status; + zend_string *user, *pass; - switch (status) { - case MEMCACHED_SUCCESS: - case MEMCACHED_STORED: - case MEMCACHED_DELETED: - case MEMCACHED_STAT: - result = 0; - intern->memc_errno = 0; - break; + if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &user, &pass) == FAILURE) { + return; + } - case MEMCACHED_END: - case MEMCACHED_BUFFERED: - intern->rescode = status; - intern->memc_errno = 0; - result = 0; - break; + if (!php_memc_init_sasl_if_needed()) { + RETURN_FALSE; + } - case MEMCACHED_SOME_ERRORS: - intern->rescode = status; - intern->memc_errno = memcached_last_error_errno(intern->memc); - result = 0; - break; + MEMC_METHOD_FETCH_OBJECT; - default: - intern->rescode = status; - intern->memc_errno = memcached_last_error_errno(intern->memc); - result = -1; - break; + if (!memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) { + php_error_docref(NULL, E_WARNING, "SASL is only supported with binary protocol"); + RETURN_FALSE; } + memc_user_data->has_sasl_data = 1; + status = memcached_set_sasl_auth_data(intern->memc, user->val, pass->val); - return result; + if (s_memc_status_handle_result_code(intern, status) == FAILURE) { + RETURN_FALSE; + } + RETURN_TRUE; } +/* }}} */ +#endif /* HAVE_MEMCACHED_SASL */ -static -zend_bool s_compress_value (enum memcached_compression_type compression_type, zend_string **payload_in, uint32_t *flags) +/* {{{ Memcached::getResultCode() + Returns the result code from the last operation */ +static PHP_METHOD(Memcached, getResultCode) { - /* status */ - zend_bool compress_status = 0; - zend_string *payload = *payload_in; + MEMC_METHOD_INIT_VARS; - /* Additional 5% for the data */ - size_t buffer_size = (size_t) (((double) payload->len * 1.05) + 1.0); - char *buffer = emalloc(buffer_size); + if (zend_parse_parameters_none() == FAILURE) { + return; + } - /* Store compressed size here */ - size_t compressed_size = 0; - uint32_t original_size = payload->len; + MEMC_METHOD_FETCH_OBJECT; - switch (compression_type) { + RETURN_LONG(intern->rescode); +} +/* }}} */ - case COMPRESSION_TYPE_FASTLZ: - { - compressed_size = fastlz_compress(payload->val, payload->len, buffer); +/* {{{ Memcached::getResultMessage() + Returns the result message from the last operation */ +static PHP_METHOD(Memcached, getResultMessage) +{ + MEMC_METHOD_INIT_VARS; - if (compressed_size > 0) { - compress_status = 1; - MEMC_VAL_SET_FLAG(*flags, MEMC_VAL_COMPRESSION_FASTLZ); - } - } - break; + if (zend_parse_parameters_none() == FAILURE) { + return; + } - case COMPRESSION_TYPE_ZLIB: - { - compressed_size = buffer_size; - int status = compress((Bytef *) buffer, &compressed_size, (Bytef *) payload->val, payload->len); + MEMC_METHOD_FETCH_OBJECT; - if (status == Z_OK) { - compress_status = 1; - MEMC_VAL_SET_FLAG(*flags, MEMC_VAL_COMPRESSION_ZLIB); - } - } + switch (intern->rescode) { + case MEMC_RES_PAYLOAD_FAILURE: + RETURN_STRING("PAYLOAD FAILURE"); break; + case MEMCACHED_ERRNO: + case MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE: + case MEMCACHED_UNKNOWN_READ_FAILURE: + if (intern->memc_errno) { + zend_string *str = strpprintf(0, "%s: %s", + memcached_strerror(intern->memc, (memcached_return)intern->rescode), strerror(intern->memc_errno)); + RETURN_STR(str); + } + /* Fall through */ default: - compress_status = 0; + RETURN_STRING(memcached_strerror(intern->memc, (memcached_return)intern->rescode)); break; } - if (!compress_status) { - php_error_docref(NULL, E_WARNING, "could not compress value"); - MEMC_VAL_DEL_FLAG(*flags, MEMC_VAL_COMPRESSED); - efree (buffer); - return 0; - } +} +/* }}} */ - /* This means the value was too small to be compressed, still a success */ - if (compressed_size > (payload->len * MEMC_G(compression_factor))) { - efree(buffer); - MEMC_VAL_DEL_FLAG(*flags, MEMC_VAL_COMPRESSED); - return 1; - } +/* {{{ Memcached::isPersistent() + Returns the true if instance uses a persistent connection */ +static PHP_METHOD(Memcached, isPersistent) +{ + MEMC_METHOD_INIT_VARS; - payload = zend_string_realloc(payload, compressed_size + sizeof(uint32_t), 0); + if (zend_parse_parameters_none() == FAILURE) { + return; + } - /* Copy the uin32_t at the beginning */ - memcpy(payload->val, &original_size, sizeof(uint32_t)); - memcpy(payload->val + sizeof (uint32_t), buffer, compressed_size); - efree(buffer); + MEMC_METHOD_FETCH_OBJECT; - zend_string_forget_hash_val(payload); - *payload_in = payload; - return 1; + RETURN_BOOL(memc_user_data->is_persistent); } +/* }}} */ -static -zend_bool s_serialize_value (enum memcached_serializer serializer, zval *value, smart_str *buf, uint32_t *flags) +/* {{{ Memcached::isPristine() + Returns the true if instance is recently created */ +static PHP_METHOD(Memcached, isPristine) { - switch (serializer) { + MEMC_METHOD_INIT_VARS; - /* - Igbinary serialization - */ -#ifdef HAVE_MEMCACHED_IGBINARY - case SERIALIZER_IGBINARY: - { - uint8_t *buffer; - size_t buffer_len; + if (zend_parse_parameters_none() == FAILURE) { + return; + } - if (igbinary_serialize(&buffer, &buffer_len, value) != 0) { - php_error_docref(NULL, E_WARNING, "could not serialize value with igbinary"); - return 0; - } - smart_str_appendl (buf, buffer, buffer_len); - efree(buffer); - MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_IGBINARY); - } - break; -#endif + MEMC_METHOD_FETCH_OBJECT; - /* - JSON serialization - */ -#ifdef HAVE_JSON_API - case SERIALIZER_JSON: - case SERIALIZER_JSON_ARRAY: - { - php_json_encode(buf, value, 0); - MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_JSON); - } - break; -#endif + RETURN_BOOL(intern->is_pristine); +} +/* }}} */ - /* - msgpack serialization - */ -#ifdef HAVE_MEMCACHED_MSGPACK - case SERIALIZER_MSGPACK: - php_msgpack_serialize(buf, value); - if (!buf->s) { - php_error_docref(NULL, E_WARNING, "could not serialize value with msgpack"); - return 0; - } - MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_MSGPACK); - break; +/**************************************** + Internal support code +****************************************/ + +/* {{{ constructor/destructor */ +static +void php_memc_destroy(memcached_st *memc, php_memc_user_data_t *memc_user_data) +{ +#if HAVE_MEMCACHED_SASL + if (memc_user_data->has_sasl_data) { + memcached_destroy_sasl_auth_data(memc); + } #endif - /* - PHP serialization - */ - default: - { - php_serialize_data_t var_hash; - PHP_VAR_SERIALIZE_INIT(var_hash); - php_var_serialize(buf, value, &var_hash); - PHP_VAR_SERIALIZE_DESTROY(var_hash); + memcached_free(memc); + pefree(memc_user_data, memc_user_data->is_persistent); +} - if (!buf->s) { - php_error_docref(NULL, E_WARNING, "could not serialize value"); - return 0; - } - MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_SERIALIZED); +static +void php_memc_object_free_storage(zend_object *object) +{ + php_memc_object_t *intern = php_memc_fetch_object(object); + + if (intern->memc) { + php_memc_user_data_t *memc_user_data = memcached_get_user_data(intern->memc); + + if (!memc_user_data->is_persistent) { + php_memc_destroy(intern->memc, memc_user_data); } - break; } - /* Check for exceptions caused by serializers */ - if (EG(exception) && buf->s->len) { - return 0; - } - return 1; + intern->memc = NULL; + zend_object_std_dtor(&intern->zo); } static -zend_string *s_zval_to_payload(zval *value, uint32_t *flags, enum memcached_serializer serializer, enum memcached_compression_type compression_type) +zend_object *php_memc_object_new(zend_class_entry *ce) { - zend_string *payload; + php_memc_object_t *intern = ecalloc(1, sizeof(php_memc_object_t) + zend_object_properties_size(ce)); - switch (Z_TYPE_P(value)) { + zend_object_std_init(&intern->zo, ce); + object_properties_init(&intern->zo, ce); - case IS_STRING: - payload = zval_get_string(value); - MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_STRING); - MEMC_VAL_HAS_FLAG(*flags, MEMC_VAL_COMPRESSED); - break; + intern->zo.handlers = &memcached_object_handlers; + return &intern->zo; +} - case IS_LONG: - { - smart_str buffer = {0}; - smart_str_append_long (&buffer, Z_LVAL_P(value)); - smart_str_0(&buffer); - payload = buffer.s; +#ifdef HAVE_MEMCACHED_PROTOCOL +static +void php_memc_server_free_storage(php_memc_server_t *intern) +{ + zend_object_std_dtor(&intern->zo); + efree (intern); +} - MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_LONG); - } - break; +zend_object_value php_memc_server_new(zend_class_entry *ce) +{ + zend_object_value retval; + php_memc_server_t *intern; + zval *tmp; - case IS_DOUBLE: - { - char buffer[40]; - php_memcached_g_fmt(buffer, Z_DVAL_P(value)); - payload = zend_string_init (buffer, strlen (buffer), 0); - MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_DOUBLE); - } - break; + intern = ecalloc(1, sizeof(php_memc_server_t)); + zend_object_std_init(&intern->zo, ce); + object_properties_init(&intern->zo, ce); - case IS_TRUE: - payload = zend_string_init ("1", 1, 0); - MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_BOOL); - break; + intern->handler = php_memc_proto_handler_new (); - case IS_FALSE: - payload = zend_string_alloc (0, 0); - MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_BOOL); - break; + retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)php_memc_server_free_storage, NULL); + retval.handlers = &memcached_server_object_handlers; - default: - { - smart_str buffer = {0}; + return retval; +} +#endif - if (!s_serialize_value (serializer, value, &buffer, flags)) { - smart_str_free(&buffer); - return NULL; - } - payload = buffer.s; - MEMC_VAL_HAS_FLAG(*flags, MEMC_VAL_COMPRESSED); - } - break; +ZEND_RSRC_DTOR_FUNC(php_memc_dtor) +{ + if (res->ptr) { + memcached_st *memc = (memcached_st *) res->ptr; + php_memc_destroy(memc, memcached_get_user_data(memc)); + res->ptr = NULL; } - zend_string_forget_hash_val(payload); +} - /* turn off compression for values below the threshold */ - if (payload->len == 0 || payload->len < MEMC_G(compression_threshold)) { - MEMC_VAL_DEL_FLAG(*flags, MEMC_VAL_COMPRESSED); - } +/* }}} */ - /* If we have compression flag, compress the value */ - if (MEMC_VAL_HAS_FLAG(*flags, MEMC_VAL_COMPRESSED)) { - /* status */ - if (!s_compress_value (compression_type, &payload, flags)) { - zend_string_release(payload); - return NULL; - } - } +/* {{{ internal API functions */ +static +memcached_return s_server_cursor_list_servers_cb(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context) +{ + zval array; + zval *return_value = (zval *) in_context; - return payload; + array_init(&array); + add_assoc_string(&array, "host", memcached_server_name(instance)); + add_assoc_long(&array, "port", memcached_server_port(instance)); + add_assoc_string(&array, "type", memcached_server_type(instance)); + /* + * API does not allow to get at this field. + add_assoc_long(array, "weight", instance->weight); + */ + + add_next_index_zval(return_value, &array); + return MEMCACHED_SUCCESS; +} + +static +memcached_return s_server_cursor_version_cb(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context) +{ + char *address, *version; + size_t address_len, version_len; + + zval *return_value = (zval *) in_context; + +#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x01000009 + version_len = spprintf(&version, sizeof(version), "%d.%d.%d", + memcached_server_major_version(instance), + memcached_server_minor_version(instance), + memcached_server_micro_version(instance)); +#else + version_len = spprintf(&version, sizeof(version) - 1, "%d.%d.%d", + instance->major_version, + instance->minor_version, + instance->micro_version); +#endif + + address_len = spprintf(&address, 0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance) - 1); + add_assoc_stringl_ex(return_value, address, address_len, version, version_len); + + efree(address); + efree(version); + return MEMCACHED_SUCCESS; } + static zend_string *s_decompress_value (const char *payload, size_t payload_len, uint32_t flags) { @@ -3559,145 +3594,6 @@ zend_class_entry *php_memc_get_exception_base(int root) #endif } -static -memcached_return s_invoke_cache_callback(zval *zobject, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string *key, zval *value) -{ - memcached_return rc = MEMCACHED_SUCCESS; - int result; - - zval params[4]; - zval retval; - zval zv_key, ref_val; - zval ref_expiration, zv_expiration; - - /* Prepare params */ - ZVAL_STR(&zv_key, key); - - ZVAL_NULL(&ref_val); - ZVAL_NULL(&zv_expiration); - - ZVAL_NEW_REF(&ref_val, value); - ZVAL_NEW_REF(&ref_expiration, &zv_expiration); - - ZVAL_COPY(¶ms[0], zobject); - ZVAL_COPY(¶ms[1], &zv_key); - ZVAL_COPY_VALUE(¶ms[2], &ref_val); - ZVAL_COPY_VALUE(¶ms[3], &ref_expiration); - - fci->retval = &retval; - fci->params = params; - fci->param_count = 4; - - result = zend_call_function(fci, fcc); - ZVAL_DUP(value, Z_REFVAL(ref_val)); - - if (result == SUCCESS && Z_TYPE(retval) != IS_UNDEF) { - - if (zend_is_true(&retval)) { - time_t expiration; - zend_string *payload; - uint32_t flags = 0; - php_memc_object_t *intern; - php_memc_user_data_t *memc_user_data; - - intern = Z_MEMC_OBJ_P(zobject); - memc_user_data = memcached_get_user_data(intern->memc); - - expiration = zval_get_long(Z_REFVAL(ref_expiration)); - payload = s_zval_to_payload(value, &flags, memc_user_data->serializer, memc_user_data->compression_type); - - if (payload == NULL) { - rc = (memcached_return) MEMC_RES_PAYLOAD_FAILURE; - } else { - if (memc_user_data->set_udf_flags >= 0) { - MEMC_VAL_SET_USER_FLAGS(flags, ((uint32_t) memc_user_data->set_udf_flags)); - } - rc = memcached_set(intern->memc, key->val, key->len, payload->val, payload->len, expiration, flags); - if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_BUFFERED) { - rc = MEMCACHED_SOME_ERRORS; - } - zend_string_release(payload); - } - } else { - rc = MEMCACHED_NOTFOUND; - zval_dtor(value); - ZVAL_NULL(value); - } - } - - if (!Z_ISUNDEF(retval)) { - zval_ptr_dtor(&retval); - } - - zval_ptr_dtor(&zv_key); - zval_ptr_dtor(&ref_val); - zval_ptr_dtor(&zv_expiration); - zval_ptr_dtor(&ref_expiration); - zval_ptr_dtor(zobject); - return rc; -} - - -static -int s_invoke_result_callback(zval *zmemc_obj, zend_fcall_info *fci, zend_fcall_info_cache *fcc, memcached_result_st *result) -{ - const char *res_key = NULL; - size_t res_key_len = 0; - const char *payload = NULL; - size_t payload_len = 0; - zval value; - zval retval; - uint64_t cas = 0; - zval z_result; - uint32_t flags = 0; - int rc = 0; - php_memc_object_t *intern = NULL; - - fci->retval = &retval; - fci->param_count = 2; - - payload = memcached_result_value(result); - payload_len = memcached_result_length(result); - flags = memcached_result_flags(result); - res_key = memcached_result_key_value(result); - res_key_len = memcached_result_key_length(result); - cas = memcached_result_cas(result); - - intern = Z_MEMC_OBJ_P(zmemc_obj); - - if (!s_memcached_result_to_zval(intern->memc, result, &value)) { - intern->rescode = MEMC_RES_PAYLOAD_FAILURE; - return -1; - } - - array_init(&z_result); - add_assoc_stringl_ex(&z_result, ZEND_STRL("key"), (char *)res_key, res_key_len); - add_assoc_zval_ex(&z_result, ZEND_STRL("value"), &value); - if (cas != 0) { - add_assoc_double_ex(&z_result, ZEND_STRL("cas"), (double)cas); - } - if (MEMC_VAL_GET_USER_FLAGS(flags) != 0) { - add_assoc_long_ex(&z_result, ZEND_STRL("flags"), MEMC_VAL_GET_USER_FLAGS(flags)); - } - - ZVAL_UNDEF(&retval); - zend_fcall_info_argn(fci, 2, zmemc_obj, &z_result); - - if (zend_call_function(fci, fcc) == FAILURE) { - php_error_docref(NULL, E_WARNING, "could not invoke result callback"); - rc = -1; - } - - if (Z_TYPE(retval) != IS_UNDEF) { - zval_ptr_dtor(&retval); - } - - zend_fcall_info_args_clear(fci, 1); - zval_ptr_dtor(&z_result); - - return rc; -} -/* }}} */ #ifdef HAVE_MEMCACHED_PROTOCOL @@ -4181,7 +4077,6 @@ PHP_GINIT_FUNCTION(php_memcached) php_memcached_globals->session.lock_wait_min = 1000; php_memcached_globals->session.lock_retries = 5; php_memcached_globals->session.lock_expiration = 30; - php_memcached_globals->session.compression_enabled = 1; php_memcached_globals->session.binary_protocol_enabled = 1; php_memcached_globals->session.consistent_hash_enabled = 1; php_memcached_globals->session.number_of_replicas = 0; @@ -4196,10 +4091,10 @@ PHP_GINIT_FUNCTION(php_memcached) #endif php_memcached_globals->memc.serializer_name = NULL; - php_memcached_globals->memc.serializer = SERIALIZER_DEFAULT; - php_memcached_globals->memc.compression_type = NULL; + php_memcached_globals->memc.serializer_type = SERIALIZER_DEFAULT; + php_memcached_globals->memc.compression_name = NULL; php_memcached_globals->memc.compression_threshold = 2000; - php_memcached_globals->memc.compression_type_real = COMPRESSION_TYPE_FASTLZ; + php_memcached_globals->memc.compression_type = COMPRESSION_TYPE_FASTLZ; php_memcached_globals->memc.compression_factor = 1.30; php_memcached_globals->memc.store_retry_count = 2; diff --git a/php_memcached_private.h b/php_memcached_private.h index c6c0b77c..d19fe974 100644 --- a/php_memcached_private.h +++ b/php_memcached_private.h @@ -75,13 +75,24 @@ typedef unsigned long int uint32_t; /**************************************** Structures and definitions ****************************************/ -enum memcached_serializer { - SERIALIZER_PHP = 1, - SERIALIZER_IGBINARY = 2, - SERIALIZER_JSON = 3, +typedef enum { + SERIALIZER_PHP = 1, + SERIALIZER_IGBINARY = 2, + SERIALIZER_JSON = 3, SERIALIZER_JSON_ARRAY = 4, - SERIALIZER_MSGPACK = 5, -}; + SERIALIZER_MSGPACK = 5 +} php_memc_serializer_type; + +typedef enum { + COMPRESSION_TYPE_ZLIB = 1, + COMPRESSION_TYPE_FASTLZ = 2 +} php_memc_compression_type; + +typedef struct { + const char *name; + php_memc_serializer_type type; +} php_memc_serializer; + #ifdef HAVE_MEMCACHED_IGBINARY #define SERIALIZER_DEFAULT SERIALIZER_IGBINARY #define SERIALIZER_DEFAULT_NAME "igbinary" @@ -160,14 +171,14 @@ ZEND_BEGIN_MODULE_GLOBALS(php_memcached) struct { char *serializer_name; - char *compression_type; + char *compression_name; zend_long compression_threshold; double compression_factor; zend_long store_retry_count; /* Converted values*/ - enum memcached_serializer serializer; - zend_long compression_type_real; + php_memc_serializer_type serializer_type; + php_memc_compression_type compression_type; /* Whether we have initialised sasl for this process */ zend_bool sasl_initialised; diff --git a/tests/getdelayed.phpt b/tests/getdelayed.phpt index 7479e97b..c07acada 100644 --- a/tests/getdelayed.phpt +++ b/tests/getdelayed.phpt @@ -22,42 +22,61 @@ foreach ($data as $k => $v) { function myfunc() { $datas = func_get_args(); if (isset($datas[1])) { - unset($datas[1]['cas']); var_dump($datas[1]); } } -$m->getDelayed(array_keys($data), false, 'myfunc'); +$m->getDelayed(array_keys($data), true, 'myfunc'); ?> ---EXPECT-- -array(2) { +--EXPECTF-- +array(4) { ["key"]=> string(3) "foo" ["value"]=> string(8) "foo-data" + ["cas"]=> + int(%d) + ["flags"]=> + int(0) } -array(2) { +array(4) { ["key"]=> string(3) "bar" ["value"]=> string(8) "bar-data" + ["cas"]=> + int(%d) + ["flags"]=> + int(0) } -array(2) { +array(4) { ["key"]=> string(3) "baz" ["value"]=> string(8) "baz-data" + ["cas"]=> + int(%d) + ["flags"]=> + int(0) } -array(2) { +array(4) { ["key"]=> string(3) "lol" ["value"]=> string(8) "lol-data" + ["cas"]=> + int(%d) + ["flags"]=> + int(0) } -array(2) { +array(4) { ["key"]=> string(3) "kek" ["value"]=> string(8) "kek-data" -} + ["cas"]=> + int(%d) + ["flags"]=> + int(0) +} \ No newline at end of file diff --git a/tests/incrdecr_invalid_key.phpt b/tests/incrdecr_invalid_key.phpt index 8d4ab671..cd8c6b9b 100644 --- a/tests/incrdecr_invalid_key.phpt +++ b/tests/incrdecr_invalid_key.phpt @@ -9,6 +9,7 @@ $m = memc_get_instance (); var_dump($m->increment('', 1)); var_dump($m->decrement('', 1)); +?> --EXPECT-- bool(false) bool(false) From 27a22f3c0ab62f98d4e01e43caf2ad80840043fd Mon Sep 17 00:00:00 2001 From: Manabu Matsui Date: Mon, 8 Feb 2016 15:35:46 +0900 Subject: [PATCH 063/104] fix expiration --- php_memcached_session.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/php_memcached_session.c b/php_memcached_session.c index bfb34e99..6dcb4cbe 100644 --- a/php_memcached_session.c +++ b/php_memcached_session.c @@ -25,6 +25,8 @@ extern ZEND_DECLARE_MODULE_GLOBALS(php_memcached) #define MEMC_SESS_DEFAULT_LOCK_WAIT 150000 #define MEMC_SESS_LOCK_EXPIRATION 30 +#define REALTIME_MAXDELTA 60*60*24*30 + ps_module ps_mod_memcached = { PS_MOD_UPDATE_TIMESTAMP(memcached) }; @@ -92,16 +94,26 @@ int php_memc_session_minit(int module_number) return SUCCESS; } +static +time_t s_adjust_expiration(zend_long expiration) +{ + if (expiration <= REALTIME_MAXDELTA) { + return expiration; + } else { + return time(NULL) + expiration; + } +} + static time_t s_lock_expiration() { if (MEMC_SESS_INI(lock_expiration) > 0) { - return time(NULL) + MEMC_SESS_INI(lock_expiration); + return s_adjust_expiration(MEMC_SESS_INI(lock_expiration)); } else { zend_long max_execution_time = zend_ini_long(ZEND_STRS("max_execution_time"), 0); if (max_execution_time > 0) { - return time(NULL) + max_execution_time; + return s_adjust_expiration(max_execution_time); } } return 0; @@ -111,7 +123,7 @@ static time_t s_session_expiration(zend_long maxlifetime) { if (maxlifetime > 0) { - return time(NULL) + maxlifetime; + return s_adjust_expiration(maxlifetime); } return 0; } From 27fa80fb260ee7d71b3562051d5a16c3f1fd1da0 Mon Sep 17 00:00:00 2001 From: Paul Werelds Date: Fri, 12 Feb 2016 15:50:58 +0100 Subject: [PATCH 064/104] Adds a missed SASL presence constraint --- php_memcached_session.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php_memcached_session.c b/php_memcached_session.c index 6dcb4cbe..61738559 100644 --- a/php_memcached_session.c +++ b/php_memcached_session.c @@ -68,9 +68,11 @@ void s_destroy_mod_data(memcached_st *memc) { php_memcached_user_data *user_data = memcached_get_user_data(memc); +#if HAVE_MEMCACHED_SASL if (user_data->has_sasl_data) { memcached_destroy_sasl_auth_data(memc); } +#endif memcached_free(memc); pefree(memc, user_data->is_persistent); From 4ff385988358f12c577ac1a7d9282600d6992b25 Mon Sep 17 00:00:00 2001 From: Mikko Date: Wed, 17 Feb 2016 14:30:43 +0100 Subject: [PATCH 065/104] Update package.xml for release --- package.xml | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/package.xml b/package.xml index 9d3be440..8ec578a7 100644 --- a/package.xml +++ b/package.xml @@ -21,7 +21,7 @@ http://pear.php.net/dtd/package-2.0.xsd"> mkoppanen@php.net yes - 2016-02-01 + 2016-02-17 3.0.0b1 3.0.0 @@ -33,17 +33,19 @@ http://pear.php.net/dtd/package-2.0.xsd"> PHP PHP7 release of memcached extension. Note that support for libmemcached 0.x series has been discontinued -and the earliest actively tested version is 1.0.2. It is highly recommended to use version 1.0.18 of -libmemcached. +and the oldest actively tested version is 1.0.2. It is highly recommended to use version 1.0.18 of +libmemcached. Please note that this is a beta release and reporting any issues would be highly appreciated +before we move closer to releasing stable version. API - * set/get commands do not take cas or user flags parameters + * set/get commands do not take cas or user flags parameters. * get and getMulti commands take Memcached::GET_EXTENDED flag to retrieve user flags and cas tokens * Fixes getStats command to return all stats from all servers * Fixes allKeys command behaviour * Fixes error where cache callback for get command was not setting expiration time properly * Added server type to server list * Remove use_sasl ini-variable and initialise sasl as needed + * CAS tokens are returned as integers and they overflow to strings as needed Session handler * Session lock algorithm updated (new ini-values memcached.sess_lock_wait_min, memcached.sess_lock_wait_max and memcached.sess_lock_retries) @@ -52,7 +54,7 @@ Session handler * Fixes crash with session_regenerate_id (work-around for PHP bug) Tests - * Fix several broken tests + * Fix several problematic tests @@ -161,6 +163,7 @@ Tests + @@ -188,21 +191,22 @@ Tests 3.0.0b1 3.0.0 - 2016-02-01 + 2016-02-17 PHP7 release of memcached extension. Note that support for libmemcached 0.x series has been discontinued -and the earliest actively tested version is 1.0.2. It is highly recommended to use version 1.0.18 of -libmemcached. +and the oldest actively tested version is 1.0.2. It is highly recommended to use version 1.0.18 of +libmemcached. Please note that this is a beta release and reporting any issues would be highly appreciated +before we move closer to releasing stable version. API - * set/get commands do not take cas or user flags parameters + * set/get commands do not take cas or user flags parameters. * get and getMulti commands take Memcached::GET_EXTENDED flag to retrieve user flags and cas tokens * Fixes getStats command to return all stats from all servers * Fixes allKeys command behaviour * Fixes error where cache callback for get command was not setting expiration time properly * Added server type to server list * Remove use_sasl ini-variable and initialise sasl as needed - * CAS tokens are returned as integers and in case of too large values they overflow to strings + * CAS tokens are returned as integers and they overflow to strings as needed Session handler * Session lock algorithm updated (new ini-values memcached.sess_lock_wait_min, memcached.sess_lock_wait_max and memcached.sess_lock_retries) @@ -211,7 +215,7 @@ Session handler * Fixes crash with session_regenerate_id (work-around for PHP bug) Tests - * Fix several broken tests + * Fix several problematic tests From 6ace07da69a5ebc021e56a9d2f52cdc8897b4f23 Mon Sep 17 00:00:00 2001 From: Mikko Date: Wed, 17 Feb 2016 14:39:49 +0100 Subject: [PATCH 066/104] Tests for default behavior --- php_memcached.c | 49 ++++++++++++++++++++++++++++++++++--- php_memcached_private.h | 9 ++++++- tests/default_behavior.phpt | 32 ++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 tests/default_behavior.phpt diff --git a/php_memcached.c b/php_memcached.c index c01b7f94..04e330fc 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -341,6 +341,11 @@ PHP_INI_BEGIN() MEMC_INI_ENTRY("compression_threshold", "2000", OnUpdateLong, compression_threshold) MEMC_INI_ENTRY("serializer", SERIALIZER_DEFAULT_NAME, OnUpdateSerializer, serializer_name) MEMC_INI_ENTRY("store_retry_count", "2", OnUpdateLong, store_retry_count) + + MEMC_INI_ENTRY("default_consistent_hash", "0", OnUpdateBool, default_behavior.consistent_hash_enabled) + MEMC_INI_ENTRY("default_binary_protocol", "0", OnUpdateBool, default_behavior.binary_protocol_enabled) + MEMC_INI_ENTRY("default_connect_timeout", "0", OnUpdateLongGEZero, default_behavior.connect_timeout) + PHP_INI_END() /* }}} */ @@ -1190,7 +1195,8 @@ static PHP_METHOD(Memcached, __construct) } if (!intern->memc) { - // TODO: handle allocation fail + php_error_docref(NULL, E_ERROR, "Failed to allocate memory for memcached structure"); + /* never reached */ } memc_user_data = pecalloc (1, sizeof(*memc_user_data), is_persistent); @@ -1203,6 +1209,38 @@ static PHP_METHOD(Memcached, __construct) memcached_set_user_data(intern->memc, memc_user_data); + /* Set default behaviors */ + { +#ifdef mikko_0 + fprintf (stderr, "consistent_hash_enabled=%d binary_protocol_enabled=%d connect_timeout=%ld\n", + MEMC_G(default_behavior.consistent_hash_enabled), MEMC_G(default_behavior.binary_protocol_enabled), MEMC_G(default_behavior.connect_timeout)); +#endif + + memcached_return rc; + + if (MEMC_G(default_behavior.consistent_hash_enabled)) { + + rc = memcached_behavior_set(intern->memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, MEMCACHED_DISTRIBUTION_CONSISTENT); + if (rc != MEMCACHED_SUCCESS) { + php_error_docref(NULL, E_WARNING, "Failed to turn on consistent hash: %s", memcached_strerror(intern->memc, rc)); + } + } + + if (MEMC_G(default_behavior.binary_protocol_enabled)) { + rc = memcached_behavior_set(intern->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1); + if (rc != MEMCACHED_SUCCESS) { + php_error_docref(NULL, E_WARNING, "Failed to turn on binary protocol: %s", memcached_strerror(intern->memc, rc)); + } + } + + if (MEMC_G(default_behavior.connect_timeout)) { + rc = memcached_behavior_set(intern->memc, MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT, MEMC_G(default_behavior.connect_timeout)); + if (rc != MEMCACHED_SUCCESS) { + php_error_docref(NULL, E_WARNING, "Failed to set connect timeout: %s", memcached_strerror(intern->memc, rc)); + } + } + } + if (fci.size) { if (!s_invoke_new_instance_cb(getThis(), &fci, &fci_cache, persistent_id) || EG(exception)) { /* error calling or exception thrown from callback */ @@ -2263,7 +2301,7 @@ PHP_METHOD(Memcached, addServer) } MEMC_METHOD_FETCH_OBJECT; - intern->rescode = MEMCACHED_SUCCESS; + s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x01000002 if (host->val[0] == '/') { /* unix domain socket */ @@ -2712,7 +2750,7 @@ static PHP_METHOD(Memcached, flush) } MEMC_METHOD_FETCH_OBJECT; - intern->rescode = MEMCACHED_SUCCESS; + s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); status = memcached_flush(intern->memc, delay); if (s_memc_status_handle_result_code(intern, status) == FAILURE) { @@ -4100,6 +4138,11 @@ PHP_GINIT_FUNCTION(php_memcached) php_memcached_globals->memc.sasl_initialised = 0; php_memcached_globals->no_effect = 0; + + /* Defaults for certain options */ + php_memcached_globals->memc.default_behavior.consistent_hash_enabled = 0; + php_memcached_globals->memc.default_behavior.binary_protocol_enabled = 0; + php_memcached_globals->memc.default_behavior.connect_timeout = 0; } zend_module_entry memcached_module_entry = { diff --git a/php_memcached_private.h b/php_memcached_private.h index d19fe974..329afc8d 100644 --- a/php_memcached_private.h +++ b/php_memcached_private.h @@ -150,7 +150,6 @@ ZEND_BEGIN_MODULE_GLOBALS(php_memcached) zend_long lock_retries; zend_long lock_expiration; - zend_bool compression_enabled; zend_bool binary_protocol_enabled; zend_bool consistent_hash_enabled; @@ -183,6 +182,14 @@ ZEND_BEGIN_MODULE_GLOBALS(php_memcached) /* Whether we have initialised sasl for this process */ zend_bool sasl_initialised; + struct { + + zend_bool consistent_hash_enabled; + zend_bool binary_protocol_enabled; + zend_long connect_timeout; + + } default_behavior; + } memc; /* For deprecated values */ diff --git a/tests/default_behavior.phpt b/tests/default_behavior.phpt new file mode 100644 index 00000000..de46cec2 --- /dev/null +++ b/tests/default_behavior.phpt @@ -0,0 +1,32 @@ +--TEST-- +Default behaviors +--SKIPIF-- + +--FILE-- +getOption(Memcached::OPT_DISTRIBUTION) == Memcached::DISTRIBUTION_MODULA); +var_dump ($m->getOption(Memcached::OPT_BINARY_PROTOCOL) == false); +var_dump ($m->getOption(Memcached::OPT_CONNECT_TIMEOUT) != 0); + +ini_set('memcached.default_consistent_hash', true); +ini_set('memcached.default_binary_protocol', true); +ini_set('memcached.default_connect_timeout', 1212); + +$m = new Memcached(); +var_dump ($m->getOption(Memcached::OPT_DISTRIBUTION) == Memcached::DISTRIBUTION_CONSISTENT); +var_dump ($m->getOption(Memcached::OPT_BINARY_PROTOCOL) == true); +var_dump ($m->getOption(Memcached::OPT_CONNECT_TIMEOUT) == 1212); + +echo "OK"; + +?> +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +OK From 3537b50d2548eb9d884cb8e980456bdfc9594523 Mon Sep 17 00:00:00 2001 From: Mikko Date: Mon, 22 Feb 2016 20:17:57 +0000 Subject: [PATCH 067/104] Update for release --- package.xml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/package.xml b/package.xml index 8ec578a7..40f0323f 100644 --- a/package.xml +++ b/package.xml @@ -21,14 +21,14 @@ http://pear.php.net/dtd/package-2.0.xsd"> mkoppanen@php.net yes - 2016-02-17 + 2016-02-22 - 3.0.0b1 + 3.0.0a1 3.0.0 - beta - beta + alpha + alpha PHP @@ -38,7 +38,7 @@ libmemcached. Please note that this is a beta release and reporting any issues w before we move closer to releasing stable version. API - * set/get commands do not take cas or user flags parameters. + * get commands do not take cas or user flags parameters. * get and getMulti commands take Memcached::GET_EXTENDED flag to retrieve user flags and cas tokens * Fixes getStats command to return all stats from all servers * Fixes allKeys command behaviour @@ -184,14 +184,14 @@ Tests - beta - beta + alpha + alpha - 3.0.0b1 + 3.0.0a1 3.0.0 - 2016-02-17 + 2016-02-22 PHP7 release of memcached extension. Note that support for libmemcached 0.x series has been discontinued and the oldest actively tested version is 1.0.2. It is highly recommended to use version 1.0.18 of @@ -199,7 +199,7 @@ libmemcached. Please note that this is a beta release and reporting any issues w before we move closer to releasing stable version. API - * set/get commands do not take cas or user flags parameters. + * get commands do not take cas or user flags parameters. * get and getMulti commands take Memcached::GET_EXTENDED flag to retrieve user flags and cas tokens * Fixes getStats command to return all stats from all servers * Fixes allKeys command behaviour From 9b8126c043c79d75b3a160735a66572e5debdb0a Mon Sep 17 00:00:00 2001 From: xjewer Date: Thu, 3 Mar 2016 23:43:20 +0300 Subject: [PATCH 068/104] fix arginfo_get* --- php_memcached.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php_memcached.c b/php_memcached.c index 04e330fc..ced03752 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -3716,12 +3716,14 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_get, 0, 0, 1) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, cache_cb) + ZEND_ARG_INFO(0, get_flags) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_getByKey, 0, 0, 2) ZEND_ARG_INFO(0, server_key) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, cache_cb) + ZEND_ARG_INFO(0, get_flags) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_getMulti, 0, 0, 1) From 4ee38195289edfa7ae936d2b0a434869c97d8817 Mon Sep 17 00:00:00 2001 From: Mikko Date: Sat, 5 Mar 2016 18:22:05 +0000 Subject: [PATCH 069/104] Fixes crash --- php_memcached.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/php_memcached.c b/php_memcached.c index 04e330fc..804af76f 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -1339,6 +1339,11 @@ static void s_clear_keys(php_memc_keys_t *keys) { size_t i; + + if (!keys->num_valid_keys) { + return; + } + for (i = 0; i < keys->num_valid_keys; i++) { zend_string_release (keys->strings[i]); } From 4bb264e60005e19b5573822d9d374b4cde8d1c3b Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Sun, 20 Mar 2016 15:37:27 -0700 Subject: [PATCH 070/104] Document ini settings for the default memcached connection configurations This documents memcached.default_consistent_hash, default_binary_protocol, and default_connect_timeout. For issue #233 --- memcached.ini | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/memcached.ini b/memcached.ini index 1aa9f266..e70c6b41 100644 --- a/memcached.ini +++ b/memcached.ini @@ -111,3 +111,32 @@ memcached.serializer = "igbinary" ; environment. ; the default is 2 memcached.store_retry_count = 2 + +; Sets the default for consistent hashing for new connections. +; (To configure consistent hashing for session connections, +; use memcached.sess_consistent_hash instead) +; +; If set to On, consistent hashing (libketama) is used +; for session handling. +; When consistent hashing is used, one can add or remove cache +; node(s) without messing up too much with existing keys +; default is Off +memcached.default_consistent_hash = Off + +; Sets the default memcached protocol for new connections. +; (To configure the memcached protocol for connections used by sessions, +; use memcached.sess_binary_protocol instead) +; +; If set to On, the memcached binary protocol is used by default. +; If set to Off, the memcached text protocol is used. +; Default is Off +memcached.default_binary_protocol = Off + +; Sets the default memcached connection timeout for new connections. +; (To configure the memcached connection timeout for sessions, +; use memcached.sess_connect_timeout instead) +; In non-blocking mode this changes the value of the timeout. +; during socket connection in milliseconds. Specifying -1 means an infinite timeout. +; Specifying 0 means using the memcached library's default connection timeout. +; Default is 0. +memcached.default_connect_timeout = 0 From e755d9db127d946740314d48dd01c81f43df0a7b Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Sun, 20 Mar 2016 15:16:35 -0700 Subject: [PATCH 071/104] Document miscellaneous ini settings and new defaults for PHP7 release This updates some of the memcached.ini documentation settings to reflect the default ini settings used in php_memcached.c. Some new settings were added, and other settings had changes to their defaults. There are other new/updated settings, which can be changed in other PRs. For issue #233 --- memcached.ini | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/memcached.ini b/memcached.ini index 1aa9f266..68f0a1ab 100644 --- a/memcached.ini +++ b/memcached.ini @@ -12,11 +12,17 @@ memcached.sess_locking = On ; The minimum time, in milliseconds, to wait between session lock attempts. ; This value is double on each lock retry until memcached.sess_lock_wait_max -; is reached -memcached.sess_lock_wait_min = 0; +; is reached, after which any further retries will take sess_lock_wait_max seconds. +; Default is 1000. +memcached.sess_lock_wait_min = 1000; ; The maximum time, in milliseconds, to wait between session lock attempts. -memcached.sess_lock_wait_max = 0; +; Default is 2000. +memcached.sess_lock_wait_max = 2000; + +; The number of times to retry locking the session lock, not including the first attempt. +; Default is 5. +memcached.sess_lock_retries = 5; ; The time, in seconds, before a lock should release itself. ; Setting to 0 results in the default behaviour, which is to @@ -29,16 +35,24 @@ memcached.sess_lock_expire = 0; ; the default value is "memc.sess.key." memcached.sess_prefix = "memc.sess.key." +; Whether or not to re-use the memcached connections corresponding to the value(s) +; of session.save_path after the execution of the script ends. +; Don't use this if certain settings (e.g. SASL settings, sess_binary_protocol) would +; be overridden between requests. +; Default is Off. +memcached.sess_persistent = Off + ; memcached session consistent hash mode ; if set to On, consistent hashing (libketama) is used ; for session handling. ; When consistent hashing is used, one can add or remove cache ; node(s) without messing up too much with existing keys -; default is Off -memcached.sess_consistent_hash = Off +; default is On +memcached.sess_consistent_hash = On -; Allow failed memcached server to automatically be removed -memcached.sess_remove_failed = 1 +; Allow failed memcached server to automatically be removed. +; Default is Off. (In previous versions, this setting was called memcached.sess_remove_failed) +memcached.sess_remove_failed_servers = Off ; Write data to a number of additional memcached servers ; This is "poor man's HA" as libmemcached calls it. @@ -57,7 +71,7 @@ memcached.sess_binary = Off memcached.sess_randomize_replica_read = Off ; memcached connect timeout value -; In non-blocking mode this changes the value of the timeout +; In non-blocking mode this changes the value of the timeout ; during socket connection in milliseconds. Specifying -1 means an infinite timeout. memcached.sess_connect_timeout = 1000 From b86282c5d6b7bacb435b4a49e5b986409a1c7c8a Mon Sep 17 00:00:00 2001 From: David Zuelke Date: Fri, 18 Mar 2016 20:40:14 +0100 Subject: [PATCH 072/104] add missing releases (and dates for all) to changelog --- ChangeLog | 76 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 45 insertions(+), 31 deletions(-) diff --git a/ChangeLog b/ChangeLog index b9b00ea5..05f77181 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,17 @@ memcached extension changelog -Version 2.2.0b1 ---------------- +Version 2.2.0 (2014-04-01) +-------------------------- + * Added the OPT_SERVER_TIMEOUT_LIMIT behaviour + +Version 2.2.0RC1 (2014-03-12) +----------------------------- + * Added the OPT_SERVER_TIMEOUT_LIMIT behaviour + * Fixes incorrect size when compressing serialized objects + * Fixes endianess of compressed values + +Version 2.2.0b1 (2013-10-28) +---------------------------- * Reinstate support for libememcached 0.x series * Added SASL support to session handler * Added Memcached::flushBuffers as per GH #78 @@ -20,28 +30,28 @@ Version 2.2.0b1 * Added Memcached::setBucket for virtual bucket support * Added support for msgpack serialization * Memcached::setSaslAuthData returns correct status on success - * Added support for user-defined flags in set and get operations + * Added support for user-defined flags in set and get operations -Version 2.1.0 -------------- +Version 2.1.0 (2012-08-06) +-------------------------- * Drop support for libmemcached 0.x series, now 1.0.x is required * Add support for virtual bucket distribution * Fix compilation against PHP 5.2 -Version 2.0.1 -------------- +Version 2.0.1 (2012-03-03) +-------------------------- * Fix embedded version number to be not -dev -Version 2.0.0 -------------- +Version 2.0.0 (2012-03-02) +-------------------------- * Add touch() and touchByKey() methods * Add resetServerList() and quit() methods * Support binary protocol in sessions * Make it work with libmemcached up to 1.0.4 * Test against PHP 5.4.0 -Version 2.0.0b2 ---------------- +Version 2.0.0b2 (2011-06-24) +---------------------------- * Add OPT_REMOVE_FAILED_SERVERS option. * Make it work with libmemcached up to 0.49. * Fix a case where invalid session ID could lock the script. @@ -61,8 +71,8 @@ Version 2.0.0b2 * Make increment/decrement initialize value when it is not available (when using binary protocol) -Version 2.0.0b1 ---------------- +Version 2.0.0b1 (2011-03-12) +---------------------------- * Add fastlz library that provides better/faster payload compression * Add configure switch to enable/disable JSON serialization support * Add getAllKeys() method @@ -84,23 +94,27 @@ Version 2.0.0b1 * Add 'on_new' callback to constructor * Add SASL support -Version 1.0.1 -------------- +Version 1.0.2 (2010-05-03) +-------------------------- + * Fix build for libmemcached-0.39 (memcached_server_list() issue) + +Version 1.0.1 (2010-03-11) +-------------------------- * Fix JSON API handling to account for PHP 5.2/5.3 version differences. * Add memcached.sess_locking, memcached.sess_lock_wait, and memcached.sess_prefix INI entries. * Add OPT_AUTO_EJECT_HOSTS option. -Version 1.0.0 -------------- +Version 1.0.0 (2009-07-04) +-------------------------- * First stable release. * Add getResultMessage() method. * Fix OPT_RECV_TIMEOUT definition. * Initialize Session lock wait to max execution time (if max execution time is unlimited, default to 30 seconds). -Version 0.2.0 -------------- +Version 0.2.0 (2009-06-04) +-------------------------- * Add JSON serializer support, requires PHP 5.2.10+. * Add HAVE_JSON and HAVE_IGBINARY class constants that indicate whether the respective serializers are available. @@ -114,25 +128,25 @@ Version 0.2.0 the cache when upgrading to this version. * Add several tests. -Version 0.1.5 -------------- +Version 0.1.5 (2009-03-31) +-------------------------- * Implement getVersion(). * Add support for preserving boolean value types. * Fix crash when child class does not call constructor. * Fix bug #16084 (Crash when addServers is called with an associative array). * ZTS compilation fixes. -Version 0.1.4 -------------- +Version 0.1.4 (2009-02-13) +-------------------------- * Fix compilation against PHP 5.3. * Add support for 'igbinary' serializer (Oleg Grenrus) -Version 0.1.3 -------------- +Version 0.1.3 (2009-02-06) +-------------------------- * Bludgeon bug #15896 (Memcached setMulti error) into submission. -Version 0.1.2 -------------- +Version 0.1.2 (2009-02-06) +-------------------------- * Fix bug #15896 (Memcached setMulti error). * Check for empty key in getServerByKey(). * Allow passing 'null' for callbacks. @@ -141,12 +155,12 @@ Version 0.1.2 * Allow only strings as the append/prepend value. * Remove expiration parameter from append/prepend. -Version 0.1.1 -------------- +Version 0.1.1 (2009-02-02) +-------------------------- * Add OPT_LIBKETAMA_COMPATIBLE option. * Implement addServers() method. * Swap internal compressed and serialized flags to be compatible with other clients. -Version 0.1.0 -------------- +Version 0.1.0 (2009-01-29) +-------------------------- * Initial release From ffd1c64ccc5d38c4a12d6bd880e917171a77a8da Mon Sep 17 00:00:00 2001 From: David Zuelke Date: Fri, 18 Mar 2016 20:39:57 +0100 Subject: [PATCH 073/104] remove duplicate 2.2.0b1 from package.xml --- package.xml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/package.xml b/package.xml index 40f0323f..244acfab 100644 --- a/package.xml +++ b/package.xml @@ -225,20 +225,6 @@ Tests - Added the OPT_SERVER_TIMEOUT_LIMIT behaviour - - - betastable - 2.2.0b12.2.0 - 2013-10-28 - -- Reinstate support for libememcached 0.x series -- Added SASL support to session handler -- Added Memcached::flushBuffers as per GH #78 -- Fixes GH #54: Fixed UDP server adding with newer libmemcached -- Fixed PHP bug #65334: (Segfault if uncompress value failed) -- Fixes GH #14: get with cas token fails to fetch all results -- Fixes GH #69: compiling on CentOS 6.4 with libmemcached 1.0.17 - betastable From 4c13c4721fbac47262bd04bc6de47ea9f968b103 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Sat, 2 Apr 2016 20:44:01 +0100 Subject: [PATCH 074/104] fix travis build, msgpack changed structure --- .travis/travis.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis/travis.sh b/.travis/travis.sh index 1eab43fb..453ed6be 100755 --- a/.travis/travis.sh +++ b/.travis/travis.sh @@ -79,7 +79,6 @@ function install_igbinary() { function install_msgpack() { git clone https://github.com/msgpack/msgpack-php.git pushd msgpack-php - git checkout php7 phpize ./configure make From b79eebc923795d11ecb27ba9ee32cffcea09f033 Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Sat, 2 Apr 2016 21:01:59 +0100 Subject: [PATCH 075/104] fix ci img in readme [ci skip] --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index e827e6fa..bb76f076 100644 --- a/README.markdown +++ b/README.markdown @@ -1,6 +1,6 @@ Build Status ------------ -[![Build Status](https://travis-ci.org/php-memcached-dev/php-memcached.png?branch=master)](https://travis-ci.org/php-memcached-dev/php-memcached) +[![Build Status](https://travis-ci.org/php-memcached-dev/php-memcached.png?branch=php7)](https://travis-ci.org/php-memcached-dev/php-memcached) Description ----------- From 6ee96cad7be5caa1f13a1f3e5a4d5f900b9c04ce Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Mon, 4 Apr 2016 06:40:56 +0100 Subject: [PATCH 076/104] Fix #238 (memory errors in s_stat_execute_cb) --- php_memcached.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index 9bff2fa8..dcf1f0da 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -2635,8 +2635,7 @@ memcached_return s_stat_execute_cb (php_memcached_instance_st instance, const ch zval zv; array_init(&zv); - server_values = &zv; - add_assoc_zval_ex(return_value, server_key, server_key_len, server_values); + server_values = zend_hash_str_add(Z_ARRVAL_P(return_value), server_key, server_key_len, &zv); } spprintf (&buffer, 0, "%.*s", value_length, value); From f31ad20468a8b0ccdd57cf8028b807bd887b4089 Mon Sep 17 00:00:00 2001 From: Konstantin Leboev Date: Tue, 10 May 2016 13:25:28 +0300 Subject: [PATCH 077/104] Check the existence of an error, and only then if it is the maximum value. --- php_memcached.c | 4 ++-- tests/incrdecr.phpt | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index dcf1f0da..d9879f8c 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -2248,11 +2248,11 @@ static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key, } } - if (value == UINT64_MAX) { + if (s_memc_status_handle_result_code(intern, status) == FAILURE) { RETURN_FALSE; } - if (s_memc_status_handle_result_code(intern, status) == FAILURE) { + if (value == UINT64_MAX) { RETURN_FALSE; } diff --git a/tests/incrdecr.phpt b/tests/incrdecr.phpt index 3addcfd3..4a30daa6 100644 --- a/tests/incrdecr.phpt +++ b/tests/incrdecr.phpt @@ -10,8 +10,11 @@ $m = memc_get_instance (); echo "Not there\n"; $m->delete('foo'); var_dump($m->increment('foo', 1)); +var_dump($m->getResultCode()); var_dump($m->decrement('foo', 1)); +var_dump($m->getResultCode()); var_dump($m->get('foo')); +var_dump($m->getResultCode()); echo "Normal\n"; $m->set('foo', 1); @@ -37,8 +40,11 @@ var_dump($m->get('foo')); --EXPECT-- Not there bool(false) +int(16) bool(false) +int(16) bool(false) +int(16) Normal int(1) int(2) From d9b2c9f38410471adc5775543ac11aa5021b7647 Mon Sep 17 00:00:00 2001 From: Dick Tang Date: Thu, 9 Jun 2016 00:43:42 +0800 Subject: [PATCH 078/104] fix: null-terminated zend_string in s_decompress_value --- php_memcached.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/php_memcached.c b/php_memcached.c index dcf1f0da..72db2cb2 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -3443,6 +3443,8 @@ zend_string *s_decompress_value (const char *payload, size_t payload_len, uint32 decompress_status = (uncompress((Bytef *) buffer->val, &buffer->len, (Bytef *)payload, payload_len) == Z_OK); } + ZSTR_VAL(buffer)[stored_length] = '\0'; + if (!decompress_status) { php_error_docref(NULL, E_WARNING, "could not decompress value"); zend_string_release (buffer); From 0e517902d63ed82a9390bd8094d546f52899ce9f Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Thu, 21 Jul 2016 18:59:01 +0800 Subject: [PATCH 079/104] Improved the tests --- tests/001.phpt | 2 +- tests/add.phpt | 2 +- tests/append.phpt | 2 +- tests/bad_construct.phpt | 2 +- tests/bug_16084.phpt | 2 +- tests/bug_16959.phpt | 2 +- tests/bug_17137.phpt | 2 +- tests/bug_18639.phpt | 6 +++--- tests/cachecallback.phpt | 2 +- tests/callback_exception.phpt | 2 +- tests/callback_exception_2.phpt | 2 +- tests/cas.phpt | 2 +- tests/cas_multi.phpt | 2 +- tests/check_if_persistent.phpt | 2 +- tests/check_if_pristine.phpt | 2 +- tests/clone.phpt | 2 +- tests/compression_types.phpt | 2 +- tests/conf_persist.phpt | 2 +- tests/config.inc | 4 +++- tests/construct.phpt | 2 +- tests/construct_persistent.phpt | 2 +- tests/default_behavior.phpt | 2 +- tests/deleted.phpt | 2 +- tests/deletemulti.phpt | 2 +- tests/deletemultitypes.phpt | 2 +- tests/experimental/add_bykey.phpt | 6 +++--- tests/experimental/addserver_unixdomain.phpt | 2 +- tests/experimental/append_bykey.phpt | 6 +++--- tests/experimental/cas_bykey.phpt | 6 +++--- tests/experimental/cas_invalid_key.phpt | 6 +++--- tests/experimental/delete_bykey.phpt | 6 +++--- tests/experimental/deletemulti_nonstringkeys.phpt | 7 +++---- tests/experimental/extreme_floats.phpt | 6 +++--- tests/experimental/fetch.phpt | 6 +++--- tests/experimental/fetch_badunserialize.phpt | 6 +++--- tests/experimental/fetchall_badunserialize.phpt | 6 +++--- tests/experimental/get.phpt | 6 +++--- tests/experimental/get_bykey.phpt | 6 +++--- tests/experimental/get_bykey_cas.phpt | 6 +++--- tests/experimental/get_udp.phpt | 6 +++--- tests/experimental/getdelayed_badserver.phpt | 2 +- tests/experimental/getdelayed_badunserialize.phpt | 6 +++--- tests/experimental/getdelayed_bykey.phpt | 6 +++--- tests/experimental/getdelayed_bykey_cas.phpt | 6 +++--- tests/experimental/getdelayed_cbthrows.phpt | 6 +++--- tests/experimental/getdelayed_nonstring_keys.phpt | 6 +++--- tests/experimental/getmulti_badserver.phpt | 2 +- tests/experimental/getmulti_badunserialize.phpt | 6 +++--- tests/experimental/getmulti_bykey.phpt | 6 +++--- tests/experimental/getmulti_empty.phpt | 6 +++--- tests/experimental/getmulti_partial_error.phpt | 6 +++--- tests/experimental/getversion.phpt | 5 +++-- tests/experimental/locale_float.phpt | 13 +++++++------ tests/experimental/moduleinfo.phpt | 4 ++-- tests/experimental/prepend_bykey.phpt | 6 +++--- tests/experimental/replace_bykey.phpt | 6 +++--- tests/experimental/serializer/serializer_php.phpt | 6 +++--- .../serializer/serializer_php_bad_serialize.phpt | 6 +++--- .../serializer/serializer_php_bad_unserialize.phpt | 12 ++++++------ tests/experimental/serializer_igbinary.phpt | 2 +- tests/experimental/serializer_json.phpt | 2 +- tests/experimental/session_gc.phpt | 5 ++++- tests/experimental/set_bykey.phpt | 6 +++--- tests/experimental/set_comp_below_factor.phpt | 6 +++--- tests/experimental/set_default_serializer.phpt | 2 +- tests/experimental/set_invalid_serializer.phpt | 2 +- tests/experimental/setget_zero_factor.phpt | 6 +++--- tests/experimental/setmulti_badserialize.phpt | 6 +++--- tests/experimental/setmulti_bykey.phpt | 6 +++--- tests/experimental/stats.phpt | 2 +- tests/experimental/stats_badserver.phpt | 2 +- tests/expire.phpt | 2 +- tests/flush_buffers.phpt | 2 +- tests/get_flags.phpt | 2 +- tests/getdelayed.phpt | 2 +- tests/getmulti.phpt | 2 +- tests/getserverbykey.phpt | 2 +- tests/getserverlist.phpt | 2 +- tests/gh_155.phpt | 3 +-- tests/gh_21.phpt | 2 +- tests/gh_77.phpt | 2 +- tests/gh_90.phpt | 2 +- tests/gh_93.phpt | 2 +- tests/incrdecr.phpt | 2 +- tests/incrdecr_bykey.phpt | 2 +- tests/incrdecr_initial.phpt | 2 +- tests/incrdecr_invalid_key.phpt | 2 +- tests/invalid_options.phpt | 2 +- tests/invoke_callback.phpt | 6 +++--- tests/invoke_callback_2.phpt | 2 +- tests/invoke_callback_twice.phpt | 2 +- tests/keys.phpt | 2 +- tests/localserver.phpt | 2 +- tests/multi_order.phpt | 2 +- tests/no-not-found.phpt | 2 +- tests/options.phpt | 2 +- tests/pr_75.phpt | 2 +- tests/prepend.phpt | 2 +- tests/replace.phpt | 2 +- tests/rescode.phpt | 2 +- tests/session_badconf_emptyprefix.phpt | 2 +- tests/session_badconf_locktime.phpt | 2 +- tests/session_badconf_prefix.phpt | 2 +- tests/session_badconf_servers.phpt | 2 +- tests/session_basic.phpt | 2 +- tests/session_basic2.phpt | 2 +- tests/session_basic3.phpt | 2 +- tests/session_lock.phpt | 2 +- tests/session_regenerate.phpt | 2 +- tests/set_large.phpt | 2 +- tests/setmulti.phpt | 2 +- tests/setoptions.phpt | 2 +- tests/stats.phpt | 2 +- tests/touch_binary.phpt | 2 +- tests/types_igbinary.phpt | 2 +- tests/types_igbinary_multi.phpt | 2 +- tests/types_json.phpt | 2 +- tests/types_json_multi.phpt | 2 +- tests/types_msgpack.phpt | 2 +- tests/types_msgpack_multi.phpt | 2 +- tests/types_php.phpt | 2 +- tests/types_php_multi.phpt | 2 +- tests/undefined_set.phpt | 2 +- tests/user-flags.phpt | 2 +- tests/vbucket.phpt | 4 ++-- tests/version.phpt | 2 +- 126 files changed, 214 insertions(+), 209 deletions(-) diff --git a/tests/001.phpt b/tests/001.phpt index d5085cd5..a66d6df3 100644 --- a/tests/001.phpt +++ b/tests/001.phpt @@ -1,7 +1,7 @@ --TEST-- Check for memcached presence --SKIPIF-- - + --FILE-- + --FILE-- + --FILE-- + --FILE-- + --FILE-- array ( 'KEYHERE' => 'localhost', 11211, 3 ), ); diff --git a/tests/bug_16959.phpt b/tests/bug_16959.phpt index f03a7091..2411e15a 100644 --- a/tests/bug_16959.phpt +++ b/tests/bug_16959.phpt @@ -1,7 +1,7 @@ --TEST-- Memcached: Bug #16959 (getMulti + BINARY_PROTOCOL problem) --SKIPIF-- - + --FILE-- + --FILE-- + --FILE-- getServerByKey('1')); bool(true) array(3) { ["host"]=> - string(9) "127.0.0.1" + string(9) "%s" ["port"]=> - int(11211) + int(%d) ["weight"]=> int(%r[01]%r) } diff --git a/tests/cachecallback.phpt b/tests/cachecallback.phpt index 31a736b7..41edfc5c 100644 --- a/tests/cachecallback.phpt +++ b/tests/cachecallback.phpt @@ -1,7 +1,7 @@ --TEST-- Memcached::get() with cache callback --SKIPIF-- - + --FILE-- + --FILE-- + --FILE-- + --FILE-- + --FILE-- --FILE-- --FILE-- + --FILE-- + --FILE-- + --FILE-- addServer($host, $port); - $memcached->flush (); + if ($memcached->flush() === false) { + return NULL; + } return $memcached; } diff --git a/tests/construct.phpt b/tests/construct.phpt index c5c78977..49e508e7 100644 --- a/tests/construct.phpt +++ b/tests/construct.phpt @@ -1,7 +1,7 @@ --TEST-- Memcached constructor --SKIPIF-- - + --FILE-- + --FILE-- + --FILE-- + --FILE-- + --FILE-- + --FILE-- + --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); $m->delete('foo'); var_dump($m->addByKey('foo', 'foo', 1, 10)); diff --git a/tests/experimental/addserver_unixdomain.phpt b/tests/experimental/addserver_unixdomain.phpt index aaec92ae..4848015d 100644 --- a/tests/experimental/addserver_unixdomain.phpt +++ b/tests/experimental/addserver_unixdomain.phpt @@ -1,7 +1,7 @@ --TEST-- Memcached::addServer() unix doamin socket --SKIPIF-- - + --CLEAN-- + --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); $m->setOption(Memcached::OPT_COMPRESSION, false); var_dump($m->setByKey('foo', 'foo', 'bar', 10)); diff --git a/tests/experimental/cas_bykey.phpt b/tests/experimental/cas_bykey.phpt index f33e24ad..f8c80fa5 100644 --- a/tests/experimental/cas_bykey.phpt +++ b/tests/experimental/cas_bykey.phpt @@ -1,11 +1,11 @@ --TEST-- Memcached::casByKey() --SKIPIF-- - + --FILE-- addServer('127.0.0.1', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); $m->delete('cas_test'); $cas_token = null; diff --git a/tests/experimental/cas_invalid_key.phpt b/tests/experimental/cas_invalid_key.phpt index 3a69e40e..6011c4b8 100644 --- a/tests/experimental/cas_invalid_key.phpt +++ b/tests/experimental/cas_invalid_key.phpt @@ -1,11 +1,11 @@ --TEST-- Memcached::cas() with strange key --SKIPIF-- - + --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); error_reporting(0); var_dump($m->cas(0, '', true, 10)); diff --git a/tests/experimental/delete_bykey.phpt b/tests/experimental/delete_bykey.phpt index 9a198f15..807af8ca 100644 --- a/tests/experimental/delete_bykey.phpt +++ b/tests/experimental/delete_bykey.phpt @@ -1,11 +1,11 @@ --TEST-- Memcached::deleteByKey() --SKIPIF-- - + --FILE-- addServer('127.0.0.1', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); $m->setByKey('keffe', 'eisaleeoo', "foo"); var_dump($m->getByKey('keffe', 'eisaleeoo')); diff --git a/tests/experimental/deletemulti_nonstringkeys.phpt b/tests/experimental/deletemulti_nonstringkeys.phpt index 69d56c78..2dac8920 100644 --- a/tests/experimental/deletemulti_nonstringkeys.phpt +++ b/tests/experimental/deletemulti_nonstringkeys.phpt @@ -1,12 +1,11 @@ --TEST-- Delete multi with integer keys --SKIPIF-- - + --FILE-- addServer('127.0.0.1', 11211, 1); -$m->addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); $data = array( 1 => '1-data', diff --git a/tests/experimental/extreme_floats.phpt b/tests/experimental/extreme_floats.phpt index 0d530370..80ef568d 100644 --- a/tests/experimental/extreme_floats.phpt +++ b/tests/experimental/extreme_floats.phpt @@ -1,11 +1,11 @@ --TEST-- Extreme floats: max, min, Inf, -Inf, and NaN --SKIPIF-- - + --FILE-- addServer('127.0.0.1', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); $m->set('float_inf', INF); $m->set('float_ninf', -INF); diff --git a/tests/experimental/fetch.phpt b/tests/experimental/fetch.phpt index e7eee9d3..13136c5b 100644 --- a/tests/experimental/fetch.phpt +++ b/tests/experimental/fetch.phpt @@ -1,7 +1,7 @@ --TEST-- Memcached getDelayed() and fetch() with and without cas --SKIPIF-- - + --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); $data = array( 'foo' => 'foo-data', diff --git a/tests/experimental/fetch_badunserialize.phpt b/tests/experimental/fetch_badunserialize.phpt index 36a3049e..251d2ca5 100644 --- a/tests/experimental/fetch_badunserialize.phpt +++ b/tests/experimental/fetch_badunserialize.phpt @@ -1,11 +1,11 @@ --TEST-- Memcached::fetch() with bad unserialize --SKIPIF-- - + --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); class Foo implements Serializable { public $serialize_throws = false; diff --git a/tests/experimental/fetchall_badunserialize.phpt b/tests/experimental/fetchall_badunserialize.phpt index 6108498a..e3ad3310 100644 --- a/tests/experimental/fetchall_badunserialize.phpt +++ b/tests/experimental/fetchall_badunserialize.phpt @@ -1,11 +1,11 @@ --TEST-- Memcached::fetch() with bad unserialize --SKIPIF-- - + --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); class Foo implements Serializable { public $serialize_throws = false; diff --git a/tests/experimental/get.phpt b/tests/experimental/get.phpt index 67e0b8f3..308bda98 100644 --- a/tests/experimental/get.phpt +++ b/tests/experimental/get.phpt @@ -1,11 +1,11 @@ --TEST-- Memcached::get() --SKIPIF-- - + --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); $m->delete('foo'); diff --git a/tests/experimental/get_bykey.phpt b/tests/experimental/get_bykey.phpt index 220dd44a..a392aaeb 100644 --- a/tests/experimental/get_bykey.phpt +++ b/tests/experimental/get_bykey.phpt @@ -1,11 +1,11 @@ --TEST-- Memcached::getByKey() --SKIPIF-- - + --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); $m->set('foo', 1, 10); diff --git a/tests/experimental/get_bykey_cas.phpt b/tests/experimental/get_bykey_cas.phpt index 6990927b..501b13a7 100644 --- a/tests/experimental/get_bykey_cas.phpt +++ b/tests/experimental/get_bykey_cas.phpt @@ -1,11 +1,11 @@ --TEST-- Memcached::getByKey() with CAS --SKIPIF-- - + --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); function the_callback(Memcached $memc, $key, &$value) { echo "called\n"; diff --git a/tests/experimental/get_udp.phpt b/tests/experimental/get_udp.phpt index 3e038e10..ad10a7cf 100644 --- a/tests/experimental/get_udp.phpt +++ b/tests/experimental/get_udp.phpt @@ -1,11 +1,11 @@ --TEST-- Memcached::set()/delete() UDP --SKIPIF-- - + --FILE-- addServer('127.0.0.1', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); $m_udp = new Memcached(); $m_udp->setOption(Memcached::OPT_USE_UDP, true); diff --git a/tests/experimental/getdelayed_badserver.phpt b/tests/experimental/getdelayed_badserver.phpt index dc0508fb..c4902174 100644 --- a/tests/experimental/getdelayed_badserver.phpt +++ b/tests/experimental/getdelayed_badserver.phpt @@ -1,7 +1,7 @@ --TEST-- Memcached::getDelayedByKey() with bad server --SKIPIF-- - + --FILE-- + --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); class Foo implements Serializable { public $serialize_throws = false; diff --git a/tests/experimental/getdelayed_bykey.phpt b/tests/experimental/getdelayed_bykey.phpt index 4b3ddf6b..a29f646b 100644 --- a/tests/experimental/getdelayed_bykey.phpt +++ b/tests/experimental/getdelayed_bykey.phpt @@ -1,11 +1,11 @@ --TEST-- Memcached::getDelayedByKey() --SKIPIF-- - + --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); $data = array( 'foo' => 'foo-data', diff --git a/tests/experimental/getdelayed_bykey_cas.phpt b/tests/experimental/getdelayed_bykey_cas.phpt index b874e739..43b19596 100644 --- a/tests/experimental/getdelayed_bykey_cas.phpt +++ b/tests/experimental/getdelayed_bykey_cas.phpt @@ -1,11 +1,11 @@ --TEST-- Memcached::getDelayedByKey() with CAS --SKIPIF-- - + --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); $data = array( 'foo' => 'foo-data', diff --git a/tests/experimental/getdelayed_cbthrows.phpt b/tests/experimental/getdelayed_cbthrows.phpt index 482034b6..2b71b4b4 100644 --- a/tests/experimental/getdelayed_cbthrows.phpt +++ b/tests/experimental/getdelayed_cbthrows.phpt @@ -1,11 +1,11 @@ --TEST-- Memcached::getDelayedByKey() with callback exception --SKIPIF-- - + --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); $data = array( 'foo' => 'foo-data', diff --git a/tests/experimental/getdelayed_nonstring_keys.phpt b/tests/experimental/getdelayed_nonstring_keys.phpt index 0e68344f..81363f3b 100644 --- a/tests/experimental/getdelayed_nonstring_keys.phpt +++ b/tests/experimental/getdelayed_nonstring_keys.phpt @@ -1,11 +1,11 @@ --TEST-- Memcached getDelayed non string keys --SKIPIF-- - + --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); class Bar { public function __toString() { diff --git a/tests/experimental/getmulti_badserver.phpt b/tests/experimental/getmulti_badserver.phpt index 21bbe192..a34825c2 100644 --- a/tests/experimental/getmulti_badserver.phpt +++ b/tests/experimental/getmulti_badserver.phpt @@ -1,7 +1,7 @@ --TEST-- Memcached::getMulti() bad server --SKIPIF-- - + --FILE-- + --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); class Foo implements Serializable { public function __sleep() { diff --git a/tests/experimental/getmulti_bykey.phpt b/tests/experimental/getmulti_bykey.phpt index 70ae01c5..e4eb112c 100644 --- a/tests/experimental/getmulti_bykey.phpt +++ b/tests/experimental/getmulti_bykey.phpt @@ -1,11 +1,11 @@ --TEST-- Memcached::getMultiByKey() --SKIPIF-- - + --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); $m->set('foo', 1, 10); $m->set('bar', 2, 10); diff --git a/tests/experimental/getmulti_empty.phpt b/tests/experimental/getmulti_empty.phpt index 7c8621da..6279104d 100644 --- a/tests/experimental/getmulti_empty.phpt +++ b/tests/experimental/getmulti_empty.phpt @@ -1,11 +1,11 @@ --TEST-- Memcached::getMulti() with empty array --SKIPIF-- - + --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); $v = $m->getMulti(array()); var_dump($v); diff --git a/tests/experimental/getmulti_partial_error.phpt b/tests/experimental/getmulti_partial_error.phpt index dc4daa50..fa392e9e 100644 --- a/tests/experimental/getmulti_partial_error.phpt +++ b/tests/experimental/getmulti_partial_error.phpt @@ -1,11 +1,11 @@ --TEST-- Memcached::getMulti() partial error --SKIPIF-- - + --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); $data = array(); for ($i = 0; $i < 1000; $i++) { diff --git a/tests/experimental/getversion.phpt b/tests/experimental/getversion.phpt index 509ff5d5..55d06714 100644 --- a/tests/experimental/getversion.phpt +++ b/tests/experimental/getversion.phpt @@ -1,13 +1,14 @@ --TEST-- Memcached::getVersion() --SKIPIF-- - + --FILE-- getVersion()); -$m->addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . "/config.inc"; +$m = memc_get_instance (); $stats = $m->getVersion(); var_dump($stats); diff --git a/tests/experimental/locale_float.phpt b/tests/experimental/locale_float.phpt index e6967bdb..9c512124 100644 --- a/tests/experimental/locale_float.phpt +++ b/tests/experimental/locale_float.phpt @@ -2,14 +2,15 @@ Float should not consider locale --SKIPIF-- addServer('127.0.0.1', 11211); + +include dirname (__FILE__) . '/config.inc'; +$memcache = memc_get_instance (); setlocale(LC_NUMERIC, "fi_FI", 'sv_SV', 'nl_NL'); diff --git a/tests/experimental/moduleinfo.phpt b/tests/experimental/moduleinfo.phpt index a1f59b44..0f02a570 100644 --- a/tests/experimental/moduleinfo.phpt +++ b/tests/experimental/moduleinfo.phpt @@ -2,7 +2,7 @@ Memcached::phpinfo() --SKIPIF-- --FILE-- @@ -35,4 +35,4 @@ memcached.sess_prefix => %s => %s memcached.sess_randomize_replica_read => %d => %d memcached.sess_remove_failed => %d => %d %rmemcached.use_sasl => %d => %d -|%rmemcached.store_retry_count => %d => %d \ No newline at end of file +|%rmemcached.store_retry_count => %d => %d diff --git a/tests/experimental/prepend_bykey.phpt b/tests/experimental/prepend_bykey.phpt index 85b12f98..87d3fd38 100644 --- a/tests/experimental/prepend_bykey.phpt +++ b/tests/experimental/prepend_bykey.phpt @@ -1,11 +1,11 @@ --TEST-- Memcached::appendByKey() --SKIPIF-- - + --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); $m->setOption(Memcached::OPT_COMPRESSION, false); var_dump($m->setByKey('foo', 'foo', 'bar', 10)); diff --git a/tests/experimental/replace_bykey.phpt b/tests/experimental/replace_bykey.phpt index 1cd858fb..b2f72836 100644 --- a/tests/experimental/replace_bykey.phpt +++ b/tests/experimental/replace_bykey.phpt @@ -1,11 +1,11 @@ --TEST-- Memcached::replaceByKey() --SKIPIF-- - + --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); error_reporting(0); $m->delete('foo'); diff --git a/tests/experimental/serializer/serializer_php.phpt b/tests/experimental/serializer/serializer_php.phpt index ce3e7266..853d5bf4 100644 --- a/tests/experimental/serializer/serializer_php.phpt +++ b/tests/experimental/serializer/serializer_php.phpt @@ -2,12 +2,12 @@ Serializer basic --SKIPIF-- --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(dirname(__FILE__))) . '/config.inc'; +$m = memc_get_instance (); $serializer = Memcached::SERIALIZER_PHP; if (isset($_ENV['TEST_MEMC_SERIALIZER'])) { eval(sprintf('$serializer = %s;', $_ENV['TEST_MEMC_SERIALIZER'])); diff --git a/tests/experimental/serializer/serializer_php_bad_serialize.phpt b/tests/experimental/serializer/serializer_php_bad_serialize.phpt index 39ef4745..81e88b0c 100644 --- a/tests/experimental/serializer/serializer_php_bad_serialize.phpt +++ b/tests/experimental/serializer/serializer_php_bad_serialize.phpt @@ -2,7 +2,7 @@ Serializer: exception while serializing --SKIPIF-- addServer('localhost', 11211, 1); +include dirname(dirname(dirname(__FILE__))) . '/config.inc'; +$m = memc_get_instance (); $serializer = Memcached::SERIALIZER_PHP; if (isset($_ENV['TEST_MEMC_SERIALIZER'])) { eval(sprintf('$serializer = %s;', $_ENV['TEST_MEMC_SERIALIZER'])); diff --git a/tests/experimental/serializer/serializer_php_bad_unserialize.phpt b/tests/experimental/serializer/serializer_php_bad_unserialize.phpt index 86fba091..39d2cc37 100644 --- a/tests/experimental/serializer/serializer_php_bad_unserialize.phpt +++ b/tests/experimental/serializer/serializer_php_bad_unserialize.phpt @@ -2,10 +2,10 @@ Serializer: exception while unserializing --SKIPIF-- addServer('localhost', 11211, 1); +include dirname(dirname(dirname(__FILE__))) . '/config.inc'; +$m = memc_get_instance (); $serializer = Memcached::SERIALIZER_PHP; if (isset($_ENV['TEST_MEMC_SERIALIZER'])) { eval(sprintf('$serializer = %s;', $_ENV['TEST_MEMC_SERIALIZER'])); diff --git a/tests/experimental/serializer_igbinary.phpt b/tests/experimental/serializer_igbinary.phpt index a762121e..4d2360bc 100644 --- a/tests/experimental/serializer_igbinary.phpt +++ b/tests/experimental/serializer_igbinary.phpt @@ -2,7 +2,7 @@ Serialize igbinary --SKIPIF-- diff --git a/tests/experimental/session_gc.phpt b/tests/experimental/session_gc.phpt index 561901fc..61dc7d3d 100644 --- a/tests/experimental/session_gc.phpt +++ b/tests/experimental/session_gc.phpt @@ -2,7 +2,10 @@ Session expiration --SKIPIF-- --INI-- diff --git a/tests/experimental/set_bykey.phpt b/tests/experimental/set_bykey.phpt index fa6d6a4b..e1fec459 100644 --- a/tests/experimental/set_bykey.phpt +++ b/tests/experimental/set_bykey.phpt @@ -1,11 +1,11 @@ --TEST-- Memcached::setByKey() --SKIPIF-- - + --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); var_dump($m->setByKey('foo', 'foo', 1, 10)); echo $m->getResultMessage(), "\n"; diff --git a/tests/experimental/set_comp_below_factor.phpt b/tests/experimental/set_comp_below_factor.phpt index f3eece2f..12e6d6a4 100644 --- a/tests/experimental/set_comp_below_factor.phpt +++ b/tests/experimental/set_comp_below_factor.phpt @@ -1,11 +1,11 @@ --TEST-- Compress below factor and fail to plain. --SKIPIF-- - + --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); ini_set('memcached.compression_threshold', 100); ini_set('memcached.compression_factor', 10); diff --git a/tests/experimental/set_default_serializer.phpt b/tests/experimental/set_default_serializer.phpt index f9658736..4886e9b7 100644 --- a/tests/experimental/set_default_serializer.phpt +++ b/tests/experimental/set_default_serializer.phpt @@ -1,7 +1,7 @@ --TEST-- Set default serializer --SKIPIF-- - + --FILE-- + --FILE-- + --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); ini_set('memcached.compression_factor', 0); $array = range(1, 20000, 1); diff --git a/tests/experimental/setmulti_badserialize.phpt b/tests/experimental/setmulti_badserialize.phpt index b12b1d3a..5081eedc 100644 --- a/tests/experimental/setmulti_badserialize.phpt +++ b/tests/experimental/setmulti_badserialize.phpt @@ -1,11 +1,11 @@ --TEST-- Memcached::setMultiByKey() with bad serialize --SKIPIF-- - + --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); class Foo implements Serializable { public function __sleep() { diff --git a/tests/experimental/setmulti_bykey.phpt b/tests/experimental/setmulti_bykey.phpt index fad3db29..e3533c2f 100644 --- a/tests/experimental/setmulti_bykey.phpt +++ b/tests/experimental/setmulti_bykey.phpt @@ -1,7 +1,7 @@ --TEST-- Memcached::setMultiByKey() --SKIPIF-- - + --FILE-- addServer('localhost', 11211, 1); +include dirname(dirname(__FILE__)) . '/config.inc'; +$m = memc_get_instance (); $data = array( 'foo' => 'foo-data', diff --git a/tests/experimental/stats.phpt b/tests/experimental/stats.phpt index 4f416384..26d814ce 100644 --- a/tests/experimental/stats.phpt +++ b/tests/experimental/stats.phpt @@ -1,7 +1,7 @@ --TEST-- Memcached::getStats() --SKIPIF-- - + --FILE-- + --FILE-- --FILE-- diff --git a/tests/flush_buffers.phpt b/tests/flush_buffers.phpt index 989a4b63..a345edce 100644 --- a/tests/flush_buffers.phpt +++ b/tests/flush_buffers.phpt @@ -1,7 +1,7 @@ --TEST-- Test flushing buffers --SKIPIF-- - + --FILE-- + --FILE-- + --FILE-- + --FILE-- + --FILE-- + --FILE-- array ( 'KEYHERE' => 'localhost', 11211, 3 ), ); diff --git a/tests/gh_155.phpt b/tests/gh_155.phpt index 643085ae..54d2b77f 100644 --- a/tests/gh_155.phpt +++ b/tests/gh_155.phpt @@ -2,8 +2,7 @@ Test for bug 155 --SKIPIF-- --FILE-- diff --git a/tests/gh_21.phpt b/tests/gh_21.phpt index 7302220e..920fb659 100644 --- a/tests/gh_21.phpt +++ b/tests/gh_21.phpt @@ -1,7 +1,7 @@ --TEST-- Test for Github issue 21 --SKIPIF-- - + --FILE-- --FILE-- diff --git a/tests/gh_90.phpt b/tests/gh_90.phpt index 9434a2d7..733b7615 100644 --- a/tests/gh_90.phpt +++ b/tests/gh_90.phpt @@ -1,7 +1,7 @@ --TEST-- Test for GH #90 --SKIPIF-- - + --FILE-- + --FILE-- + --FILE-- + --FILE-- + --FILE-- + --FILE-- + --FILE-- + --FILE-- array(3) { ["host"]=> - string(9) "127.0.0.1" + string(9) "%s" ["port"]=> - int(11211) + int(%d) ["type"]=> string(3) "TCP" } diff --git a/tests/invoke_callback_2.phpt b/tests/invoke_callback_2.phpt index 276d1c26..07e84f94 100644 --- a/tests/invoke_callback_2.phpt +++ b/tests/invoke_callback_2.phpt @@ -1,7 +1,7 @@ --TEST-- Use callback initializer --SKIPIF-- - + --FILE-- + --FILE-- + --FILE-- + --FILE-- + --FILE-- + --FILE-- + --FILE-- + --FILE-- + --FILE-- + --FILE-- + --FILE-- --INI-- diff --git a/tests/session_badconf_locktime.phpt b/tests/session_badconf_locktime.phpt index 9bda76b6..edb2a49f 100644 --- a/tests/session_badconf_locktime.phpt +++ b/tests/session_badconf_locktime.phpt @@ -1,7 +1,7 @@ --TEST-- Session bad configurations, lock wait time --SKIPIF-- - --INI-- diff --git a/tests/session_badconf_prefix.phpt b/tests/session_badconf_prefix.phpt index 093485c4..c42e8376 100644 --- a/tests/session_badconf_prefix.phpt +++ b/tests/session_badconf_prefix.phpt @@ -2,7 +2,7 @@ Session bad configurations, prefix --SKIPIF-- --INI-- diff --git a/tests/session_badconf_servers.phpt b/tests/session_badconf_servers.phpt index 9fd911cd..b5c0803b 100644 --- a/tests/session_badconf_servers.phpt +++ b/tests/session_badconf_servers.phpt @@ -2,7 +2,7 @@ Session bad configurations, invalid save path (server list) --SKIPIF-- --INI-- diff --git a/tests/session_basic.phpt b/tests/session_basic.phpt index c5a464b5..3fdb6bd7 100644 --- a/tests/session_basic.phpt +++ b/tests/session_basic.phpt @@ -2,7 +2,7 @@ Session basic open, write, destroy --SKIPIF-- --INI-- diff --git a/tests/session_basic2.phpt b/tests/session_basic2.phpt index 782ae6d3..0a06c457 100644 --- a/tests/session_basic2.phpt +++ b/tests/session_basic2.phpt @@ -2,7 +2,7 @@ Session basic open, write, destroy --SKIPIF-- --INI-- diff --git a/tests/session_basic3.phpt b/tests/session_basic3.phpt index 21288571..d684fa35 100644 --- a/tests/session_basic3.phpt +++ b/tests/session_basic3.phpt @@ -2,7 +2,7 @@ Session basic open, write, destroy --SKIPIF-- --INI-- diff --git a/tests/session_lock.phpt b/tests/session_lock.phpt index a328dd68..79c32888 100644 --- a/tests/session_lock.phpt +++ b/tests/session_lock.phpt @@ -2,7 +2,7 @@ Session lock --SKIPIF-- --INI-- diff --git a/tests/session_regenerate.phpt b/tests/session_regenerate.phpt index 794f46fc..bbd37fa2 100644 --- a/tests/session_regenerate.phpt +++ b/tests/session_regenerate.phpt @@ -2,7 +2,7 @@ Session regenerate --SKIPIF-- --INI-- diff --git a/tests/set_large.phpt b/tests/set_large.phpt index bf1098ef..f3cb4cc3 100644 --- a/tests/set_large.phpt +++ b/tests/set_large.phpt @@ -1,7 +1,7 @@ --TEST-- set large data --SKIPIF-- - + --FILE-- + --FILE-- + --FILE-- + --FILE-- --FILE-- diff --git a/tests/types_igbinary.phpt b/tests/types_igbinary.phpt index 62fcc29b..da1b26fa 100644 --- a/tests/types_igbinary.phpt +++ b/tests/types_igbinary.phpt @@ -2,7 +2,7 @@ Memcached store & fetch type and value correctness using igbinary serializer --SKIPIF-- --FILE-- diff --git a/tests/types_igbinary_multi.phpt b/tests/types_igbinary_multi.phpt index 33f4df67..2a0823e0 100644 --- a/tests/types_igbinary_multi.phpt +++ b/tests/types_igbinary_multi.phpt @@ -2,7 +2,7 @@ Memcached multi store & multi fetch type and value correctness using igbinary serializer --SKIPIF-- --FILE-- diff --git a/tests/types_json.phpt b/tests/types_json.phpt index f5735f6d..2491fea7 100644 --- a/tests/types_json.phpt +++ b/tests/types_json.phpt @@ -2,7 +2,7 @@ Memcached store & fetch type and value correctness using JSON serializer --SKIPIF-- --FILE-- diff --git a/tests/types_json_multi.phpt b/tests/types_json_multi.phpt index 6a085039..b6bc203e 100644 --- a/tests/types_json_multi.phpt +++ b/tests/types_json_multi.phpt @@ -2,7 +2,7 @@ Memcached multi store & multi fetch type and value correctness using JSON serializer --SKIPIF-- --FILE-- diff --git a/tests/types_msgpack.phpt b/tests/types_msgpack.phpt index aed43627..aad0d5bb 100644 --- a/tests/types_msgpack.phpt +++ b/tests/types_msgpack.phpt @@ -2,7 +2,7 @@ Memcached store & fetch type and value correctness using msgpack serializer --SKIPIF-- --FILE-- diff --git a/tests/types_msgpack_multi.phpt b/tests/types_msgpack_multi.phpt index dcf251e1..4ba42347 100644 --- a/tests/types_msgpack_multi.phpt +++ b/tests/types_msgpack_multi.phpt @@ -2,7 +2,7 @@ Memcached multi store & fetch type and value correctness using msgpack serializer --SKIPIF-- --FILE-- diff --git a/tests/types_php.phpt b/tests/types_php.phpt index f6baab5b..8d99f375 100644 --- a/tests/types_php.phpt +++ b/tests/types_php.phpt @@ -1,7 +1,7 @@ --TEST-- Memcached store & fetch type and value correctness using PHP serializer --SKIPIF-- - + --FILE-- + --FILE-- + --FILE-- + --FILE-- --FILE-- @@ -45,4 +45,4 @@ NULL Warning: Memcached::setBucket(): the map must contain positive integers in %s on line %d bool(false) -OK \ No newline at end of file +OK diff --git a/tests/version.phpt b/tests/version.phpt index 8ffe275a..06cd537b 100644 --- a/tests/version.phpt +++ b/tests/version.phpt @@ -1,7 +1,7 @@ --TEST-- Get version --SKIPIF-- - + --FILE-- Date: Sat, 23 Jul 2016 11:11:34 +0800 Subject: [PATCH 080/104] Added skipif.inc --- tests/skipif.inc | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tests/skipif.inc diff --git a/tests/skipif.inc b/tests/skipif.inc new file mode 100644 index 00000000..bcd32d25 --- /dev/null +++ b/tests/skipif.inc @@ -0,0 +1,10 @@ + Date: Sat, 23 Jul 2016 12:11:31 +0800 Subject: [PATCH 081/104] Cleanup --- php_memcached.c | 147 ++++++++++++++++++++++++------------------------ 1 file changed, 73 insertions(+), 74 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index 31bec912..3bd5ee48 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -241,9 +241,9 @@ static PHP_INI_MH(OnUpdateCompressionType) { if (!new_value) { MEMC_G(compression_type) = COMPRESSION_TYPE_FASTLZ; - } else if (!strcmp(new_value->val, "fastlz")) { + } else if (!strcmp(ZSTR_VAL(new_value), "fastlz")) { MEMC_G(compression_type) = COMPRESSION_TYPE_FASTLZ; - } else if (!strcmp(new_value->val, "zlib")) { + } else if (!strcmp(ZSTR_VAL(new_value), "zlib")) { MEMC_G(compression_type) = COMPRESSION_TYPE_ZLIB; } else { return FAILURE; @@ -255,20 +255,20 @@ static PHP_INI_MH(OnUpdateSerializer) { if (!new_value) { MEMC_G(serializer_type) = SERIALIZER_DEFAULT; - } else if (!strcmp(new_value->val, "php")) { + } else if (!strcmp(ZSTR_VAL(new_value), "php")) { MEMC_G(serializer_type) = SERIALIZER_PHP; #ifdef HAVE_MEMCACHED_IGBINARY - } else if (!strcmp(new_value->val, "igbinary")) { + } else if (!strcmp(ZSTR_VAL(new_value), "igbinary")) { MEMC_G(serializer_type) = SERIALIZER_IGBINARY; #endif // IGBINARY #ifdef HAVE_JSON_API - } else if (!strcmp(new_value->val, "json")) { + } else if (!strcmp(ZSTR_VAL(new_value), "json")) { MEMC_G(serializer_type) = SERIALIZER_JSON; - } else if (!strcmp(new_value->val, "json_array")) { + } else if (!strcmp(ZSTR_VAL(new_value), "json_array")) { MEMC_G(serializer_type) = SERIALIZER_JSON_ARRAY; #endif // JSON #ifdef HAVE_MEMCACHED_MSGPACK - } else if (!strcmp(new_value->val, "msgpack")) { + } else if (!strcmp(ZSTR_VAL(new_value), "msgpack")) { MEMC_G(serializer_type) = SERIALIZER_MSGPACK; #endif // msgpack } else { @@ -281,7 +281,7 @@ static PHP_INI_MH(OnUpdateSerializer) static PHP_INI_MH(OnUpdateDeprecatedLockValue) { - if (new_value->len > 0 && strcmp(new_value->val, "not set")) { + if (ZSTR_LEN(new_value) > 0 && strcmp(ZSTR_VAL(new_value), "not set")) { php_error_docref(NULL, E_DEPRECATED, "memcached.sess_lock_wait and memcached.sess_lock_max_wait are deprecated. Please update your configuration to use memcached.sess_lock_wait_min, memcached.sess_lock_wait_max and memcached.sess_lock_retries"); } return FAILURE; @@ -290,8 +290,8 @@ PHP_INI_MH(OnUpdateDeprecatedLockValue) static PHP_INI_MH(OnUpdateSessionPrefixString) { - if (new_value && new_value->len > 0) { - char *ptr = new_value->val; + if (new_value && ZSTR_LEN(new_value) > 0) { + char *ptr = ZSTR_VAL(new_value); while (*ptr != '\0') { if (isspace (*ptr++)) { @@ -299,7 +299,7 @@ PHP_INI_MH(OnUpdateSessionPrefixString) return FAILURE; } } - if (new_value->len > MEMCACHED_MAX_KEY) { + if (ZSTR_LEN(new_value) > MEMCACHED_MAX_KEY) { php_error_docref(NULL, E_WARNING, "memcached.sess_prefix too long (max: %d)", MEMCACHED_MAX_KEY - 1); return FAILURE; } @@ -672,7 +672,7 @@ zend_bool php_memc_mget_apply(php_memc_object_t *intern, zend_string *server_key } if (server_key) { - status = memcached_mget_by_key(intern->memc, server_key->val, server_key->len, keys->mkeys, keys->mkeys_len, keys->num_valid_keys); + status = memcached_mget_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), keys->mkeys, keys->mkeys_len, keys->num_valid_keys); } else { status = memcached_mget(intern->memc, keys->mkeys, keys->mkeys_len, keys->num_valid_keys); } @@ -810,18 +810,18 @@ zend_bool s_compress_value (php_memc_compression_type compression_type, zend_str zend_string *payload = *payload_in; /* Additional 5% for the data */ - size_t buffer_size = (size_t) (((double) payload->len * 1.05) + 1.0); + size_t buffer_size = (size_t) (((double) ZSTR_LEN(payload) * 1.05) + 1.0); char *buffer = emalloc(buffer_size); /* Store compressed size here */ size_t compressed_size = 0; - uint32_t original_size = payload->len; + uint32_t original_size = ZSTR_LEN(payload); switch (compression_type) { case COMPRESSION_TYPE_FASTLZ: { - compressed_size = fastlz_compress(payload->val, payload->len, buffer); + compressed_size = fastlz_compress(ZSTR_VAL(payload), ZSTR_LEN(payload), buffer); if (compressed_size > 0) { compress_status = 1; @@ -833,7 +833,7 @@ zend_bool s_compress_value (php_memc_compression_type compression_type, zend_str case COMPRESSION_TYPE_ZLIB: { compressed_size = buffer_size; - int status = compress((Bytef *) buffer, &compressed_size, (Bytef *) payload->val, payload->len); + int status = compress((Bytef *) buffer, &compressed_size, (Bytef *) ZSTR_VAL(payload), ZSTR_LEN(payload)); if (status == Z_OK) { compress_status = 1; @@ -855,7 +855,7 @@ zend_bool s_compress_value (php_memc_compression_type compression_type, zend_str } /* This means the value was too small to be compressed, still a success */ - if (compressed_size > (payload->len * MEMC_G(compression_factor))) { + if (compressed_size > (ZSTR_LEN(payload) * MEMC_G(compression_factor))) { MEMC_VAL_DEL_FLAG(*flags, MEMC_VAL_COMPRESSED); efree (buffer); return 1; @@ -864,8 +864,8 @@ zend_bool s_compress_value (php_memc_compression_type compression_type, zend_str payload = zend_string_realloc(payload, compressed_size + sizeof(uint32_t), 0); /* Copy the uin32_t at the beginning */ - memcpy(payload->val, &original_size, sizeof(uint32_t)); - memcpy(payload->val + sizeof (uint32_t), buffer, compressed_size); + memcpy(ZSTR_VAL(payload), &original_size, sizeof(uint32_t)); + memcpy(ZSTR_VAL(payload) + sizeof (uint32_t), buffer, compressed_size); efree(buffer); zend_string_forget_hash_val(payload); @@ -1014,7 +1014,7 @@ zend_string *s_zval_to_payload(php_memc_object_t *intern, zval *value, uint32_t zend_string_forget_hash_val(payload); /* turn off compression for values below the threshold */ - if (payload->len == 0 || payload->len < MEMC_G(compression_threshold)) { + if (ZSTR_LEN(payload) == 0 || ZSTR_LEN(payload) < MEMC_G(compression_threshold)) { should_compress = 0; } @@ -1063,8 +1063,8 @@ zend_bool s_memc_write_zval (php_memc_object_t *intern, php_memc_write_op op, ze } } -#define memc_write_using_fn(fn_name) payload ? fn_name(intern->memc, key->val, key->len, payload->val, payload->len, expiration, flags) : MEMC_RES_PAYLOAD_FAILURE; -#define memc_write_using_fn_by_key(fn_name) payload ? fn_name(intern->memc, server_key->val, server_key->len, key->val, key->len, payload->val, payload->len, expiration, flags) : MEMC_RES_PAYLOAD_FAILURE; +#define memc_write_using_fn(fn_name) payload ? fn_name(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(payload), ZSTR_LEN(payload), expiration, flags) : MEMC_RES_PAYLOAD_FAILURE; +#define memc_write_using_fn_by_key(fn_name) payload ? fn_name(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(payload), ZSTR_LEN(payload), expiration, flags) : MEMC_RES_PAYLOAD_FAILURE; if (server_key) { switch (op) { @@ -1073,7 +1073,7 @@ zend_bool s_memc_write_zval (php_memc_object_t *intern, php_memc_write_op op, ze break; case MEMC_OP_TOUCH: - status = memcached_touch_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, expiration); + status = memcached_touch_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), expiration); break; case MEMC_OP_ADD: @@ -1105,7 +1105,7 @@ zend_bool s_memc_write_zval (php_memc_object_t *intern, php_memc_write_op op, ze break; case MEMC_OP_TOUCH: - status = memcached_touch(intern->memc, key->val, key->len, expiration); + status = memcached_touch(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), expiration); break; case MEMC_OP_ADD: @@ -1302,12 +1302,12 @@ void s_hash_to_keys(php_memc_keys_t *keys_out, HashTable *hash_in, zend_bool pre zend_string *key = zval_get_string(zv); if (preserve_order && return_value) { - add_assoc_null_ex(return_value, key->val, key->len); + add_assoc_null_ex(return_value, ZSTR_VAL(key), ZSTR_LEN(key)); } - if (key->len > 0 && key->len < MEMCACHED_MAX_KEY) { - keys_out->mkeys[idx] = key->val; - keys_out->mkeys_len[idx] = key->len; + if (ZSTR_LEN(key) > 0 && ZSTR_LEN(key) < MEMCACHED_MAX_KEY) { + keys_out->mkeys[idx] = ZSTR_VAL(key); + keys_out->mkeys_len[idx] = ZSTR_LEN(key); keys_out->strings[idx] = key; idx++; @@ -1331,8 +1331,8 @@ void s_key_to_keys(php_memc_keys_t *keys_out, zend_string *key) { zval zv_keys; - array_init (&zv_keys); - add_next_index_stringl (&zv_keys, key->val, key->len); + array_init(&zv_keys); + add_next_index_str(&zv_keys, zend_string_copy(key)); s_hash_to_keys(keys_out, Z_ARRVAL(zv_keys), 0, NULL); zval_ptr_dtor(&zv_keys); @@ -1409,7 +1409,6 @@ void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) context.extended = (get_flags & MEMC_GET_EXTENDED); - ZVAL_UNDEF(return_value); context.return_value = return_value; s_key_to_keys(&keys, key); @@ -1461,15 +1460,15 @@ zend_bool s_get_multi_apply_fn(php_memc_object_t *intern, zend_string *key, zval Z_TRY_ADDREF_P(cas); - array_init (&node); - add_assoc_zval (&node, "value", value); - add_assoc_zval (&node, "cas", cas); - add_assoc_long (&node, "flags", (zend_long) MEMC_VAL_GET_USER_FLAGS(flags)); + array_init(&node); + add_assoc_zval(&node, "value", value); + add_assoc_zval(&node, "cas", cas); + add_assoc_long(&node, "flags", (zend_long) MEMC_VAL_GET_USER_FLAGS(flags)); - add_assoc_zval_ex(context->return_value, key->val, key->len, &node); + zend_symtable_update(Z_ARRVAL_P(context->return_value), key, &node); } else { - add_assoc_zval_ex(context->return_value, key->val, key->len, value); + zend_symtable_update(Z_ARRVAL_P(context->return_value), key, value); } return 1; } @@ -1563,10 +1562,10 @@ void s_create_result_array(zend_string *key, zval *value, zval *cas, uint32_t fl Z_TRY_ADDREF_P(value); Z_TRY_ADDREF_P(cas); - add_assoc_stringl_ex(return_value, ZEND_STRL("key"), key->val, key->len); - add_assoc_zval_ex(return_value, ZEND_STRL("value"), value); + add_assoc_str_ex(return_value, ZEND_STRL("key"), zend_string_copy(key)); + add_assoc_zval_ex(return_value, ZEND_STRL("value"), value); - add_assoc_zval_ex(return_value, ZEND_STRL("cas"), cas); + add_assoc_zval_ex(return_value, ZEND_STRL("cas"), cas); add_assoc_long_ex(return_value, ZEND_STRL("flags"), MEMC_VAL_GET_USER_FLAGS(flags)); } @@ -2029,9 +2028,9 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) } if (by_key) { - status = memcached_cas_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, payload->val, payload->len, expiration, flags, cas); + status = memcached_cas_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(payload), ZSTR_LEN(payload), expiration, flags, cas); } else { - status = memcached_cas(intern->memc, key->val, key->len, payload->val, payload->len, expiration, flags, cas); + status = memcached_cas(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(payload), ZSTR_LEN(payload), expiration, flags, cas); } zend_string_release(payload); @@ -2114,10 +2113,10 @@ static void php_memc_delete_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); if (by_key) { - status = memcached_delete_by_key(intern->memc, server_key->val, server_key->len, key->val, - key->len, expiration); + status = memcached_delete_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), + ZSTR_LEN(key), expiration); } else { - status = memcached_delete(intern->memc, key->val, key->len, expiration); + status = memcached_delete(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), expiration); } if (s_memc_status_handle_result_code(intern, status) == FAILURE) { @@ -2131,10 +2130,10 @@ static void php_memc_delete_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) /* {{{ -- php_memc_deleteMulti_impl */ static void php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { - zval *entries; + zval *entries, *zv, ret; zend_string *server_key = NULL; time_t expiration = 0; - zval *entry; + zend_string *entry; memcached_return status; MEMC_METHOD_INIT_VARS; @@ -2153,27 +2152,27 @@ static void php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); array_init(return_value); - ZEND_HASH_FOREACH_VAL (Z_ARRVAL_P(entries), entry) { - if (Z_TYPE_P(entry) != IS_STRING) { - convert_to_string_ex(entry); - } + ZEND_HASH_FOREACH_VAL (Z_ARRVAL_P(entries), zv) { + entry = zval_get_string(zv); - if (Z_STRLEN_P(entry) == 0) { + if (ZSTR_LEN(entry) == 0) { + zend_string_release(entry); continue; } if (by_key) { - status = memcached_delete_by_key(intern->memc, server_key->val, server_key->len, Z_STRVAL_P(entry), Z_STRLEN_P(entry), expiration); + status = memcached_delete_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(entry), ZSTR_LEN(entry), expiration); } else { - status = memcached_delete_by_key(intern->memc, Z_STRVAL_P(entry), Z_STRLEN_P(entry), Z_STRVAL_P(entry), Z_STRLEN_P(entry), expiration); + status = memcached_delete_by_key(intern->memc, ZSTR_VAL(entry), ZSTR_LEN(entry), ZSTR_VAL(entry), ZSTR_LEN(entry), expiration); } - if (s_memc_status_handle_result_code(intern, status) == FAILURE) { - add_assoc_long(return_value, Z_STRVAL_P(entry), status); + ZVAL_LONG(&ret, status); } else { - add_assoc_bool(return_value, Z_STRVAL_P(entry), 1); + ZVAL_TRUE(&ret); } + zend_symtable_update(Z_ARRVAL_P(return_value), entry, &ret); + zend_string_release(entry); } ZEND_HASH_FOREACH_END(); return; @@ -2213,15 +2212,15 @@ static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key, if ((!by_key && n_args < 3) || (by_key && n_args < 4)) { if (by_key) { if (incr) { - status = memcached_increment_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, (unsigned int)offset, &value); + status = memcached_increment_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, &value); } else { - status = memcached_decrement_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, (unsigned int)offset, &value); + status = memcached_decrement_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, &value); } } else { if (incr) { - status = memcached_increment(intern->memc, key->val, key->len, (unsigned int)offset, &value); + status = memcached_increment(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, &value); } else { - status = memcached_decrement(intern->memc, key->val, key->len, (unsigned int)offset, &value); + status = memcached_decrement(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, &value); } } @@ -2235,15 +2234,15 @@ static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key, } if (by_key) { if (incr) { - status = memcached_increment_with_initial_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, (unsigned int)offset, initial, expiry, &value); + status = memcached_increment_with_initial_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, initial, expiry, &value); } else { - status = memcached_decrement_with_initial_by_key(intern->memc, server_key->val, server_key->len, key->val, key->len, (unsigned int)offset, initial, expiry, &value); + status = memcached_decrement_with_initial_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, initial, expiry, &value); } } else { if (incr) { - status = memcached_increment_with_initial(intern->memc, key->val, key->len, (unsigned int)offset, initial, expiry, &value); + status = memcached_increment_with_initial(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, initial, expiry, &value); } else { - status = memcached_decrement_with_initial(intern->memc, key->val, key->len, (unsigned int)offset, initial, expiry, &value); + status = memcached_decrement_with_initial(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, initial, expiry, &value); } } if (s_should_retry_write(intern, status) && retries-- > 0) { @@ -2452,7 +2451,7 @@ PHP_METHOD(Memcached, getServerByKey) MEMC_METHOD_FETCH_OBJECT; s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); - server_instance = memcached_server_by_key(intern->memc, server_key->val, server_key->len, &error); + server_instance = memcached_server_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), &error); if (server_instance == NULL) { s_memc_status_handle_result_code(intern, error); RETURN_FALSE; @@ -2651,7 +2650,7 @@ memcached_return s_stat_execute_cb (php_memcached_instance_st instance, const ch add_assoc_double(server_values, key, d_val); } else { - add_assoc_stringl_ex(server_values, key, key_length, value, value_length); + add_assoc_stringl_ex(server_values, key, key_length, (char*)value, value_length); } efree (buffer); efree (server_key); @@ -3369,9 +3368,9 @@ memcached_return s_server_cursor_list_servers_cb(const memcached_st *ptr, php_me zval *return_value = (zval *) in_context; array_init(&array); - add_assoc_string(&array, "host", memcached_server_name(instance)); + add_assoc_string(&array, "host", (char*)memcached_server_name(instance)); add_assoc_long(&array, "port", memcached_server_port(instance)); - add_assoc_string(&array, "type", memcached_server_type(instance)); + add_assoc_string(&array, "type", (char*)memcached_server_type(instance)); /* * API does not allow to get at this field. add_assoc_long(array, "weight", instance->weight); @@ -3467,8 +3466,8 @@ zend_bool s_unserialize_value (memcached_st *memc, int val_type, zend_string *pa php_unserialize_data_t var_hash; const unsigned char *p, *max; - p = (const unsigned char *) payload->val; - max = p + payload->len; + p = (const unsigned char *) ZSTR_VAL(payload); + max = p + ZSTR_LEN(payload); PHP_VAR_UNSERIALIZE_INIT(var_hash); if (!php_var_unserialize(return_value, &p, max, &var_hash)) { @@ -3484,7 +3483,7 @@ zend_bool s_unserialize_value (memcached_st *memc, int val_type, zend_string *pa case MEMC_VAL_IS_IGBINARY: #ifdef HAVE_MEMCACHED_IGBINARY - if (igbinary_unserialize((uint8_t *) payload->val, payload->len, return_value)) { + if (igbinary_unserialize((uint8_t *) ZSTR_VAL(payload), ZSTR_LEN(payload), return_value)) { ZVAL_FALSE(return_value); php_error_docref(NULL, E_WARNING, "could not unserialize value with igbinary"); return 0; @@ -3500,7 +3499,7 @@ zend_bool s_unserialize_value (memcached_st *memc, int val_type, zend_string *pa #ifdef HAVE_JSON_API { php_memc_user_data_t *memc_user_data = memcached_get_user_data(memc); - php_json_decode(return_value, payload->val, payload->len, (memc_user_data->serializer == SERIALIZER_JSON_ARRAY), PHP_JSON_PARSER_DEFAULT_DEPTH); + php_json_decode(return_value, ZSTR_VAL(payload), ZSTR_LEN(payload), (memc_user_data->serializer == SERIALIZER_JSON_ARRAY), PHP_JSON_PARSER_DEFAULT_DEPTH); } #else ZVAL_FALSE(return_value); @@ -3511,7 +3510,7 @@ zend_bool s_unserialize_value (memcached_st *memc, int val_type, zend_string *pa case MEMC_VAL_IS_MSGPACK: #ifdef HAVE_MEMCACHED_MSGPACK - php_msgpack_unserialize(return_value, payload->val, payload->len); + php_msgpack_unserialize(return_value, ZSTR_VAL(payload), ZSTR_LEN(payload)); #else ZVAL_FALSE(return_value); php_error_docref(NULL, E_WARNING, "could not unserialize value, no msgpack support"); From 09e29e65deabae5b23fdf5db1928992d6107d9c9 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Sat, 23 Jul 2016 12:27:52 +0800 Subject: [PATCH 082/104] Fixed possible crash with opcache (We should never edit a zval in place) --- php_memcached.c | 94 +++++++++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 50 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index 3bd5ee48..078f1b25 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -1819,8 +1819,7 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); ZEND_HASH_FOREACH_KEY_VAL (Z_ARRVAL_P(entries), num_key, skey, value) { - - zend_string *str_key; + zend_string *str_key = NULL; if (skey) { str_key = skey; @@ -2337,7 +2336,6 @@ PHP_METHOD(Memcached, addServers) zval *servers; zval *entry; zval *z_host, *z_port, *z_weight = NULL; - uint32_t weight = 0; HashPosition pos; int entry_size, i = 0; memcached_server_st *list = NULL; @@ -2361,6 +2359,10 @@ PHP_METHOD(Memcached, addServers) entry_size = zend_hash_num_elements(Z_ARRVAL_P(entry)); if (entry_size > 1) { + zend_string *host; + zend_long port; + uint32_t weight; + zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(entry), &pos); /* Check that we have a host */ @@ -2378,8 +2380,8 @@ PHP_METHOD(Memcached, addServers) continue; } - convert_to_string_ex(z_host); - convert_to_long_ex(z_port); + host = zval_get_string(z_host); + port = zval_get_long(z_port); weight = 0; if (entry_size > 2) { @@ -2389,12 +2391,12 @@ PHP_METHOD(Memcached, addServers) php_error_docref(NULL, E_WARNING, "could not get server weight for entry #%d", i+1); } - convert_to_long_ex(z_weight); - weight = Z_LVAL_P(z_weight); + weight = zval_get_long(z_weight); } - list = memcached_server_list_append_with_weight(list, Z_STRVAL_P(z_host), - Z_LVAL_P(z_port), weight, &status); + list = memcached_server_list_append_with_weight(list, ZSTR_VAL(host), port, weight, &status); + + zend_string_release(host); if (s_memc_status_handle_result_code(intern, status) == SUCCESS) { i++; @@ -2839,21 +2841,21 @@ static PHP_METHOD(Memcached, getOption) static int php_memc_set_option(php_memc_object_t *intern, long option, zval *value) { + zend_long lval; memcached_return rc = MEMCACHED_FAILURE; memcached_behavior flag; php_memc_user_data_t *memc_user_data = memcached_get_user_data(intern->memc); switch (option) { case MEMC_OPT_COMPRESSION: - convert_to_long(value); - memc_user_data->compression_enabled = Z_LVAL_P(value) ? 1 : 0; + memc_user_data->compression_enabled = zval_get_long(value) ? 1 : 0; break; case MEMC_OPT_COMPRESSION_TYPE: - convert_to_long(value); - if (Z_LVAL_P(value) == COMPRESSION_TYPE_FASTLZ || - Z_LVAL_P(value) == COMPRESSION_TYPE_ZLIB) { - memc_user_data->compression_type = Z_LVAL_P(value); + lval = zval_get_long(value); + if (lval == COMPRESSION_TYPE_FASTLZ || + lval == COMPRESSION_TYPE_ZLIB) { + memc_user_data->compression_type = lval; } else { /* invalid compression type */ intern->rescode = MEMCACHED_INVALID_ARGUMENTS; @@ -2863,12 +2865,13 @@ int php_memc_set_option(php_memc_object_t *intern, long option, zval *value) case MEMC_OPT_PREFIX_KEY: { + zend_string *str; char *key; #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX == 0x00049000 char tmp[MEMCACHED_PREFIX_KEY_MAX_SIZE - 1]; #endif - convert_to_string(value); - if (Z_STRLEN_P(value) == 0) { + str = zval_get_string(value); + if (ZSTR_VAL(str) == 0) { key = NULL; } else { /* @@ -2876,25 +2879,27 @@ int php_memc_set_option(php_memc_object_t *intern, long option, zval *value) character of the key prefix, to avoid the issue we pad it with a '0' */ #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX == 0x00049000 - snprintf(tmp, sizeof(tmp), "%s0", Z_STRVAL_P(value)); + snprintf(tmp, sizeof(tmp), "%s0", ZSTR_VAL(str)); key = tmp; #else - key = Z_STRVAL_P(value); + key = ZSTR_VAL(str); #endif } if (memcached_callback_set(intern->memc, MEMCACHED_CALLBACK_PREFIX_KEY, key) == MEMCACHED_BAD_KEY_PROVIDED) { + zend_string_release(str); intern->rescode = MEMCACHED_INVALID_ARGUMENTS; php_error_docref(NULL, E_WARNING, "bad key provided"); return 0; } + zend_string_release(str); } break; case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED: flag = (memcached_behavior) option; - convert_to_long(value); - rc = memcached_behavior_set(intern->memc, flag, (uint64_t) Z_LVAL_P(value)); + lval = zval_get_long(value); + rc = memcached_behavior_set(intern->memc, flag, (uint64_t)lval); if (s_memc_status_handle_result_code(intern, rc) == FAILURE) { php_error_docref(NULL, E_WARNING, "error setting memcached option: %s", memcached_strerror (intern->memc, rc)); @@ -2906,7 +2911,7 @@ int php_memc_set_option(php_memc_object_t *intern, long option, zval *value) * options on false case, like it does for MEMCACHED_BEHAVIOR_KETAMA * (non-weighted) case. We have to clean up ourselves. */ - if (!Z_LVAL_P(value)) { + if (!lval) { #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX > 0x00037000 (void)memcached_behavior_set_key_hash(intern->memc, MEMCACHED_HASH_DEFAULT); (void)memcached_behavior_set_distribution_hash(intern->memc, MEMCACHED_HASH_DEFAULT); @@ -2920,28 +2925,28 @@ int php_memc_set_option(php_memc_object_t *intern, long option, zval *value) case MEMC_OPT_SERIALIZER: { - convert_to_long(value); + lval = zval_get_long(value); /* igbinary serializer */ #ifdef HAVE_MEMCACHED_IGBINARY - if (Z_LVAL_P(value) == SERIALIZER_IGBINARY) { + if (lval == SERIALIZER_IGBINARY) { memc_user_data->serializer = SERIALIZER_IGBINARY; } else #endif #ifdef HAVE_JSON_API - if (Z_LVAL_P(value) == SERIALIZER_JSON) { + if (lval == SERIALIZER_JSON) { memc_user_data->serializer = SERIALIZER_JSON; - } else if (Z_LVAL_P(value) == SERIALIZER_JSON_ARRAY) { + } else if (lval == SERIALIZER_JSON_ARRAY) { memc_user_data->serializer = SERIALIZER_JSON_ARRAY; } else #endif /* msgpack serializer */ #ifdef HAVE_MEMCACHED_MSGPACK - if (Z_LVAL_P(value) == SERIALIZER_MSGPACK) { + if (lval == SERIALIZER_MSGPACK) { memc_user_data->serializer = SERIALIZER_MSGPACK; } else #endif /* php serializer */ - if (Z_LVAL_P(value) == SERIALIZER_PHP) { + if (lval == SERIALIZER_PHP) { memc_user_data->serializer = SERIALIZER_PHP; } else { memc_user_data->serializer = SERIALIZER_PHP; @@ -2953,23 +2958,23 @@ int php_memc_set_option(php_memc_object_t *intern, long option, zval *value) } case MEMC_OPT_USER_FLAGS: - convert_to_long(value); + lval = zval_get_long(value); - if (Z_LVAL_P(value) < 0) { + if (lval < 0) { memc_user_data->set_udf_flags = -1; return 1; } - if (Z_LVAL_P(value) > MEMC_VAL_USER_FLAGS_MAX) { + if (lval > MEMC_VAL_USER_FLAGS_MAX) { php_error_docref(NULL, E_WARNING, "MEMC_OPT_USER_FLAGS must be < %u", MEMC_VAL_USER_FLAGS_MAX); return 0; } - memc_user_data->set_udf_flags = Z_LVAL_P(value); + memc_user_data->set_udf_flags = lval; break; case MEMC_OPT_STORE_RETRY_COUNT: - convert_to_long(value); - memc_user_data->store_retry_count = Z_LVAL_P(value); + lval = zval_get_long(value); + memc_user_data->store_retry_count = lval; break; default: @@ -2981,10 +2986,10 @@ int php_memc_set_option(php_memc_object_t *intern, long option, zval *value) } else { flag = (memcached_behavior) option; - convert_to_long(value); + lval = zval_get_long(value); if (flag < MEMCACHED_BEHAVIOR_MAX) { - rc = memcached_behavior_set(intern->memc, flag, (uint64_t) Z_LVAL_P(value)); + rc = memcached_behavior_set(intern->memc, flag, (uint64_t)lval); } else { rc = MEMCACHED_INVALID_ARGUMENTS; @@ -3016,15 +3021,9 @@ uint32_t *s_zval_to_uint32_array (zval *input, size_t *num_elements) retval = ecalloc(*num_elements, sizeof(uint32_t)); ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(input), pzval) { - long value = 0; - - if (Z_TYPE_P(pzval) == IS_LONG) { - value = Z_LVAL_P(pzval); - } else { - value = zval_get_long(pzval); - value = value > 0? value : 0; - } + zend_long value = 0; + value = zval_get_long(pzval); if (value < 0) { php_error_docref(NULL, E_WARNING, "the map must contain positive integers"); efree (retval); @@ -3126,14 +3125,9 @@ static PHP_METHOD(Memcached, setOptions) php_error_docref(NULL, E_WARNING, "invalid configuration option"); ok = 0; } else { - zval copy; - ZVAL_DUP(©, value); - - if (!php_memc_set_option(intern, (long) key_index, ©)) { + if (!php_memc_set_option(intern, (long) key_index, value)) { ok = 0; } - - zval_dtor(©); } } ZEND_HASH_FOREACH_END(); From 010d8e4894f068fda6b70d9b2dd6ada42b62beca Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Sat, 23 Jul 2016 12:33:56 +0800 Subject: [PATCH 083/104] Fixed possbile memleak --- php_memcached_server.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/php_memcached_server.c b/php_memcached_server.c index eb225db0..ad33e0bc 100644 --- a/php_memcached_server.c +++ b/php_memcached_server.c @@ -29,19 +29,15 @@ #define MEMC_MAKE_ZVAL_COOKIE(my_zcookie, my_ptr) \ do { \ - char *cookie_buf; \ - spprintf (&cookie_buf, 0, "%p", my_ptr); \ - MAKE_STD_ZVAL(my_zcookie); \ - ZVAL_STRING(my_zcookie, cookie_buf, 0); \ + zend_string *cookie_buf; \ + cookie_buf = zend_strpprintf(0, "%p", my_ptr); \ + ZVAL_STR(&my_zcookie, cookie_buf); \ } while (0) #define MEMC_MAKE_RESULT_CAS(my_zresult_cas, my_result_cas) \ do { \ my_result_cas = 0; \ - if (Z_TYPE_P(my_zresult_cas) != IS_NULL) { \ - convert_to_double (my_zresult_cas); \ - my_result_cas = (uint64_t) Z_DVAL_P(my_zresult_cas); \ - } \ + my_result_cas = zval_get_double(my_zresult_cas); \ } while (0) @@ -78,9 +74,7 @@ long s_invoke_php_callback (php_memc_server_cb_t *cb, zval ***params, ssize_t pa efree (buf); } if (retval_ptr) { - convert_to_long (retval_ptr); - retval = Z_LVAL_P(retval_ptr); - zval_ptr_dtor(&retval_ptr); + retval = zval_get_long(retval_ptr); } return retval; } @@ -223,10 +217,7 @@ protocol_binary_response_status s_incr_decr_handler (php_memc_event_t event, con retval = s_invoke_php_callback (&MEMC_GET_CB(event), params, 7); - if (Z_TYPE(zresult) != IS_LONG) { - convert_to_long (&zresult); - } - *result = (uint64_t) Z_LVAL(zresult); + *result = (uint64_t)zval_get_long(zresult); MEMC_MAKE_RESULT_CAS(zresult_cas, *result_cas); From 95f26c4f75dc9d29e5d7b1f8b4e6f8204b7db850 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Sat, 23 Jul 2016 12:38:41 +0800 Subject: [PATCH 084/104] Fixed warning in run-test.php and also fixed test --- tests/experimental/moduleinfo.phpt | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/tests/experimental/moduleinfo.phpt b/tests/experimental/moduleinfo.phpt index 0f02a570..8605c11a 100644 --- a/tests/experimental/moduleinfo.phpt +++ b/tests/experimental/moduleinfo.phpt @@ -19,20 +19,4 @@ echo implode("\n", $array); --EXPECTF-- memcached memcached support => enabled -memcached.compression_factor => %f => %f -memcached.compression_threshold => %d => %d -memcached.compression_type => %s => %s -memcached.serializer => %s => %s -memcached.sess_binary => %d => %d -memcached.sess_connect_timeout => %d => %d -memcached.sess_consistent_hash => %d => %d -memcached.sess_lock_expire => %d => %d -memcached.sess_lock_max_wait => %d => %d -memcached.sess_lock_wait => %d => %d -memcached.sess_locking => %d => %d -memcached.sess_number_of_replicas => %d => %d -memcached.sess_prefix => %s => %s -memcached.sess_randomize_replica_read => %d => %d -memcached.sess_remove_failed => %d => %d -%rmemcached.use_sasl => %d => %d -|%rmemcached.store_retry_count => %d => %d +%A From a1aab4e85576a008fd87eb50aa11668fa92842e0 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Sat, 23 Jul 2016 13:13:30 +0800 Subject: [PATCH 085/104] Avoid str duplication --- php_memcached.c | 12 ++++++------ php_memcached_server.c | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index 078f1b25..48c3cc24 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -2623,8 +2623,7 @@ zend_bool s_double_value(const char *str, double *value) static memcached_return s_stat_execute_cb (php_memcached_instance_st instance, const char *key, size_t key_length, const char *value, size_t value_length, void *context) { - char *server_key; - size_t server_key_len; + zend_string *server_key; zend_long long_val; double d_val; char *buffer; @@ -2632,14 +2631,14 @@ memcached_return s_stat_execute_cb (php_memcached_instance_st instance, const ch zval *return_value = (zval *) context; zval *server_values; - server_key_len = spprintf (&server_key, 0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance)); - server_values = zend_hash_str_find(Z_ARRVAL_P(return_value), server_key, server_key_len); + server_key = strpprintf(0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance)); + server_values = zend_hash_find(Z_ARRVAL_P(return_value), server_key); if (!server_values) { zval zv; array_init(&zv); - server_values = zend_hash_str_add(Z_ARRVAL_P(return_value), server_key, server_key_len, &zv); + server_values = zend_hash_add(Z_ARRVAL_P(return_value), server_key, &zv); } spprintf (&buffer, 0, "%.*s", value_length, value); @@ -2655,7 +2654,8 @@ memcached_return s_stat_execute_cb (php_memcached_instance_st instance, const ch add_assoc_stringl_ex(server_values, key, key_length, (char*)value, value_length); } efree (buffer); - efree (server_key); + zend_string_release(server_key); + return MEMCACHED_SUCCESS; } diff --git a/php_memcached_server.c b/php_memcached_server.c index ad33e0bc..94305101 100644 --- a/php_memcached_server.c +++ b/php_memcached_server.c @@ -30,7 +30,7 @@ #define MEMC_MAKE_ZVAL_COOKIE(my_zcookie, my_ptr) \ do { \ zend_string *cookie_buf; \ - cookie_buf = zend_strpprintf(0, "%p", my_ptr); \ + cookie_buf = strpprintf(0, "%p", my_ptr); \ ZVAL_STR(&my_zcookie, cookie_buf); \ } while (0) From 6405d96c54e41ce9020c80bfd48ab325789f29d7 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Sat, 23 Jul 2016 13:17:42 +0800 Subject: [PATCH 086/104] Msgpack master is php7 branch now --- .travis/travis.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis/travis.sh b/.travis/travis.sh index b587f5c5..d43a15fc 100755 --- a/.travis/travis.sh +++ b/.travis/travis.sh @@ -79,7 +79,7 @@ function install_igbinary() { function install_msgpack() { git clone https://github.com/msgpack/msgpack-php.git pushd msgpack-php - git checkout php5 + git checkout master phpize ./configure make From d67517b04d92464928f06402ac104bc133227d5f Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Sat, 23 Jul 2016 13:48:09 +0800 Subject: [PATCH 087/104] Fixed tests/keys.phpt --- php_memcached.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/php_memcached.c b/php_memcached.c index 48c3cc24..be9f229f 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -206,6 +206,16 @@ static inline php_memc_object_t *php_memc_fetch_object(zend_object *obj) { } \ memc_user_data = (php_memc_user_data_t *) memcached_get_user_data(intern->memc); +#define MEMC_CHECK_KEY(intern, key) \ + if (UNEXPECTED(ZSTR_LEN(key) == 0 || \ + ZSTR_LEN(key) > MEMC_OBJECT_KEY_MAX_LENGTH || \ + (memcached_behavior_get(intern->memc, \ + MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) ? \ + strchr(ZSTR_VAL(key), '\n') : \ + strchr(ZSTR_VAL(key), ' ')))) { \ + intern->rescode = MEMCACHED_BAD_KEY_PROVIDED; \ + RETURN_FALSE; \ + } #ifdef HAVE_MEMCACHED_PROTOCOL @@ -1406,6 +1416,7 @@ void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) MEMC_METHOD_FETCH_OBJECT; s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); + MEMC_CHECK_KEY(intern, key); context.extended = (get_flags & MEMC_GET_EXTENDED); @@ -1960,6 +1971,7 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool MEMC_METHOD_FETCH_OBJECT; s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); + MEMC_CHECK_KEY(intern, key); if (memc_user_data->compression_enabled) { /* @@ -2017,6 +2029,7 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) MEMC_METHOD_FETCH_OBJECT; s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); + MEMC_CHECK_KEY(intern, key); cas = s_zval_to_uint64(zv_cas); @@ -2110,6 +2123,7 @@ static void php_memc_delete_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) MEMC_METHOD_FETCH_OBJECT; s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); + MEMC_CHECK_KEY(intern, key); if (by_key) { status = memcached_delete_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), @@ -2202,6 +2216,7 @@ static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key, MEMC_METHOD_FETCH_OBJECT; s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); + MEMC_CHECK_KEY(intern, key); if (offset < 0) { php_error_docref(NULL, E_WARNING, "offset has to be > 0"); From 0acaa06d98b2447c6c981bbed7b8a500fc46188f Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Sat, 23 Jul 2016 15:14:48 +0800 Subject: [PATCH 088/104] call_function always initialized retval --- php_memcached.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index be9f229f..81dd92f3 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -613,13 +613,7 @@ memcached_return php_memc_result_apply(php_memc_object_t *intern, php_memc_resul const char *res_key; size_t res_key_len; - - ZVAL_UNDEF(&zv_value); if (!s_memcached_result_to_zval(intern->memc, &result, &zv_value)) { - if (Z_TYPE(zv_value) != IS_UNDEF) { - zval_ptr_dtor(&zv_value); - } - if (EG(exception)) { status = MEMC_RES_PAYLOAD_FAILURE; memcached_quit(intern->memc); @@ -729,8 +723,6 @@ zend_bool s_invoke_new_instance_cb(zval *object, zend_fcall_info *fci, zend_fcal ZVAL_NULL(&id); } - ZVAL_UNDEF(&retval); - zend_fcall_info_argn(fci, 2, object, &id); fci->retval = &retval; fci->no_separation = 1; @@ -784,8 +776,6 @@ zend_bool s_invoke_cache_callback(zval *zobject, zend_fcall_info *fci, zend_fcal fci->params = params; fci->param_count = 4; - ZVAL_UNDEF(&retval); - if (zend_call_function(fci, fcc) == SUCCESS) { if (zend_is_true(&retval)) { time_t expiration = zval_get_long(Z_REFVAL(ref_expiration)); @@ -1596,7 +1586,6 @@ zend_bool s_result_callback_apply(php_memc_object_t *intern, zend_string *key, z context->fci.retval = &retval; context->fci.param_count = 2; - ZVAL_UNDEF(&retval); if (zend_call_function(&context->fci, &context->fcc) == FAILURE) { if (Z_TYPE(retval) != IS_UNDEF) { zval_ptr_dtor(&retval); @@ -3597,14 +3586,10 @@ zend_bool s_memcached_result_to_zval(memcached_st *memc, memcached_result_st *re default: php_error_docref(NULL, E_WARNING, "unknown payload type"); - retval = 0; break; } zend_string_release(data); - if (!retval) { - zval_ptr_dtor(return_value); - } return retval; } From a0ed436fca84faab5a1cbe978789c7e1c97970f3 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Sat, 23 Jul 2016 15:15:30 +0800 Subject: [PATCH 089/104] According to memcached wiki, touch is added since 1.4.8 https://github.com/memcached/memcached/wiki/ReleaseNotes148 --- tests/config.inc | 5 +++++ tests/expire.phpt | 4 +++- tests/gh_155.phpt | 1 + tests/gh_77.phpt | 6 ++++-- tests/skipif.inc | 8 +++++++- tests/touch_binary.phpt | 6 ++++-- 6 files changed, 24 insertions(+), 6 deletions(-) diff --git a/tests/config.inc b/tests/config.inc index 4f275af1..a5f3cc2f 100644 --- a/tests/config.inc +++ b/tests/config.inc @@ -66,3 +66,8 @@ function memc_create_combinations ($name, $serializer, $ignore_object_type = fal ), ); } + +function memc_get_version($memc, $host = '') { + $version = $memc->getVersion(); + return array_pop($version); +} diff --git a/tests/expire.phpt b/tests/expire.phpt index 0aa1a555..eac02408 100644 --- a/tests/expire.phpt +++ b/tests/expire.phpt @@ -3,7 +3,9 @@ Memcached store, fetch & touch expired key --XFAIL-- https://code.google.com/p/memcached/issues/detail?id=275 --SKIPIF-- - --FILE-- diff --git a/tests/gh_155.phpt b/tests/gh_155.phpt index 54d2b77f..a5b61d00 100644 --- a/tests/gh_155.phpt +++ b/tests/gh_155.phpt @@ -2,6 +2,7 @@ Test for bug 155 --SKIPIF-- diff --git a/tests/gh_77.phpt b/tests/gh_77.phpt index 193b6916..8f241ff4 100644 --- a/tests/gh_77.phpt +++ b/tests/gh_77.phpt @@ -1,8 +1,10 @@ --TEST-- Test for Github issue #77 --SKIPIF-- - --FILE-- --FILE-- Date: Sat, 23 Jul 2016 15:18:54 +0800 Subject: [PATCH 090/104] Remove unused arg --- tests/config.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/config.inc b/tests/config.inc index a5f3cc2f..98747d79 100644 --- a/tests/config.inc +++ b/tests/config.inc @@ -67,7 +67,7 @@ function memc_create_combinations ($name, $serializer, $ignore_object_type = fal ); } -function memc_get_version($memc, $host = '') { +function memc_get_version($memc) { $version = $memc->getVersion(); return array_pop($version); } From 09e13048ecb813e2d0866c34d7319024d11f91b0 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Sat, 23 Jul 2016 19:48:13 +0800 Subject: [PATCH 091/104] cleanup --- php_memcached.c | 143 ++++++++++++++++-------------------------------- 1 file changed, 47 insertions(+), 96 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index 81dd92f3..2b543e73 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -58,12 +58,9 @@ #define MEMC_G(v) (php_memcached_globals.memc.v) #endif - static - int le_memc; +static int le_memc; -static -int php_memc_list_entry(void) -{ +static int php_memc_list_entry(void) { return le_memc; } @@ -379,8 +376,7 @@ static void php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key); /* Invoke PHP functions */ -static - zend_bool s_invoke_cache_callback(zval *zobject, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string *key, zval *value); +static zend_bool s_invoke_cache_callback(zval *zobject, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string *key, zval *value); /* Iterate result sets */ typedef zend_bool (*php_memc_result_apply_fn)(php_memc_object_t *intern, zend_string *key, zval *value, zval *cas, uint32_t flags, void *context); @@ -655,7 +651,6 @@ zend_bool php_memc_mget_apply(php_memc_object_t *intern, zend_string *server_key php_memc_result_apply_fn result_apply_fn, zend_bool with_cas, void *context) { memcached_return status; - memcached_result_st result; int mget_status; uint64_t orig_cas_flag = 0; @@ -715,17 +710,19 @@ static zend_bool s_invoke_new_instance_cb(zval *object, zend_fcall_info *fci, zend_fcall_info_cache *fci_cache, zend_string *persistent_id) { zend_bool ret = 1; - zval retval, id; + zval retval; + zval params[2]; + ZVAL_COPY(¶ms[0], object); if (persistent_id) { - ZVAL_STR(&id, persistent_id); + ZVAL_STR(¶ms[1], zend_string_copy(persistent_id)); } else { - ZVAL_NULL(&id); + ZVAL_NULL(¶ms[1]); } - zend_fcall_info_argn(fci, 2, object, &id); - fci->retval = &retval; - fci->no_separation = 1; + fci->retval = &retval; + fci->params = params; + fci->param_count = 2; if (zend_call_function(fci, fci_cache) == FAILURE) { char *buf = php_memc_printable_func (fci, fci_cache); @@ -734,43 +731,27 @@ zend_bool s_invoke_new_instance_cb(zval *object, zend_fcall_info *fci, zend_fcal ret = 0; } - if (Z_TYPE(retval) != IS_UNDEF) { - zval_ptr_dtor(&retval); - } + zval_ptr_dtor(¶ms[0]); + zval_ptr_dtor(¶ms[1]); + zval_ptr_dtor(&retval); - if (EG(exception)) { - ret = 0; - } - - zend_fcall_info_args_clear(fci, 1); return ret; } static zend_bool s_invoke_cache_callback(zval *zobject, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string *key, zval *value) { - memcached_return rc; zend_bool status = 0; - zval params[4]; zval retval; - zval zv_key, ref_val; - zval ref_expiration, zv_expiration; php_memc_object_t *intern = Z_MEMC_OBJ_P(zobject); /* Prepare params */ - ZVAL_STR(&zv_key, key); - - ZVAL_NULL(&ref_val); - ZVAL_NULL(&zv_expiration); - - ZVAL_NEW_REF(&ref_val, value); - ZVAL_NEW_REF(&ref_expiration, &zv_expiration); - ZVAL_COPY(¶ms[0], zobject); - ZVAL_COPY(¶ms[1], &zv_key); - ZVAL_COPY_VALUE(¶ms[2], &ref_val); - ZVAL_COPY_VALUE(¶ms[3], &ref_expiration); + ZVAL_STR(¶ms[1], zend_string_copy(key)); /* key */ + ZVAL_NEW_REF(¶ms[2], value); /* value */ + ZVAL_NEW_EMPTY_REF(¶ms[3]); /* expiration */ + ZVAL_NULL(Z_REFVAL(params[3])); fci->retval = &retval; fci->params = params; @@ -778,23 +759,22 @@ zend_bool s_invoke_cache_callback(zval *zobject, zend_fcall_info *fci, zend_fcal if (zend_call_function(fci, fcc) == SUCCESS) { if (zend_is_true(&retval)) { - time_t expiration = zval_get_long(Z_REFVAL(ref_expiration)); - status = s_memc_write_zval (intern, MEMC_OP_SET, NULL, key, Z_REFVAL(ref_val), expiration); - ZVAL_DUP(value, Z_REFVAL(ref_val)); + time_t expiration = zval_get_long(Z_REFVAL(params[3])); + status = s_memc_write_zval (intern, MEMC_OP_SET, NULL, key, Z_REFVAL(params[2]), expiration); + /* memleak? zval_ptr_dtor(value); */ + ZVAL_COPY(value, Z_REFVAL(params[2])); } } else { s_memc_set_status(intern, MEMCACHED_NOTFOUND, 0); } - zval_ptr_dtor(zobject); - zval_ptr_dtor(&zv_key); - zval_ptr_dtor(&ref_val); - zval_ptr_dtor(&ref_expiration); + zval_ptr_dtor(¶ms[0]); + zval_ptr_dtor(¶ms[1]); + zval_ptr_dtor(¶ms[2]); + zval_ptr_dtor(¶ms[3]); + zval_ptr_dtor(&retval); - if (!Z_ISUNDEF(retval)) { - zval_ptr_dtor(&retval); - } return status; } @@ -1388,7 +1368,7 @@ void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) zend_long get_flags = 0; zend_string *key; zend_string *server_key = NULL; - zend_bool extended, mget_status; + zend_bool mget_status; memcached_return status = MEMCACHED_SUCCESS; zend_fcall_info fci = empty_fcall_info; zend_fcall_info_cache fcc = empty_fcall_info_cache; @@ -1484,8 +1464,7 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke zend_string *server_key = NULL; zend_long flags = 0; MEMC_METHOD_INIT_VARS; - - zend_bool with_cas, retval, preserve_order, extended; + zend_bool retval, preserve_order; if (by_key) { if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa|l", &server_key, @@ -1574,32 +1553,29 @@ static zend_bool s_result_callback_apply(php_memc_object_t *intern, zend_string *key, zval *value, zval *cas, uint32_t flags, void *in_context) { zend_bool status = 1; - - zval retval, zv_result; + zval params[2]; + zval retval; php_memc_result_callback_ctx_t *context = (php_memc_result_callback_ctx_t *) in_context; - array_init(&zv_result); - s_create_result_array(key, value, cas, flags, &zv_result); + ZVAL_COPY(¶ms[0], context->object); + array_init(¶ms[1]); - zend_fcall_info_argn(&context->fci, 2, context->object, &zv_result); + s_create_result_array(key, value, cas, flags, ¶ms[1]); context->fci.retval = &retval; + context->fci.params = params; context->fci.param_count = 2; if (zend_call_function(&context->fci, &context->fcc) == FAILURE) { - if (Z_TYPE(retval) != IS_UNDEF) { - zval_ptr_dtor(&retval); - } php_error_docref(NULL, E_WARNING, "could not invoke result callback"); status = 0; } - if (Z_TYPE(retval) != IS_UNDEF) { - zval_ptr_dtor(&retval); - } + zval_ptr_dtor(&retval); + + zval_ptr_dtor(¶ms[0]); + zval_ptr_dtor(¶ms[1]); - zend_fcall_info_args_clear(&context->fci, 2); - zval_ptr_dtor(&zv_result); return status; } @@ -1663,14 +1639,6 @@ zend_bool s_fetch_apply(php_memc_object_t *intern, zend_string *key, zval *value Returns the next result from a previous delayed request */ PHP_METHOD(Memcached, fetch) { - const char *res_key = NULL; - size_t res_key_len = 0; - const char *payload = NULL; - size_t payload_len = 0; - uint32_t flags = 0; - uint64_t cas = 0; - zval value, zv_cas; - memcached_result_st result; memcached_return status = MEMCACHED_SUCCESS; MEMC_METHOD_INIT_VARS; @@ -1708,14 +1676,6 @@ zend_bool s_fetch_all_apply(php_memc_object_t *intern, zend_string *key, zval *v Returns all the results from a previous delayed request */ PHP_METHOD(Memcached, fetchAll) { - const char *res_key = NULL; - size_t res_key_len = 0; - const char *payload = NULL; - size_t payload_len = 0; - uint32_t flags; - uint64_t cas = 0; - zval value, entry, zv_cas; - memcached_result_st result; memcached_return status = MEMCACHED_SUCCESS; MEMC_METHOD_INIT_VARS; @@ -1794,13 +1754,8 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke zend_string *server_key = NULL; time_t expiration = 0; zval *value; - zend_string *skey, *str_key = NULL; - ulong num_key; - zend_string *payload; - uint32_t flags = 0; - uint32_t retry = 0; - memcached_return status; - char tmp_key[MEMCACHED_MAX_KEY]; + zend_string *skey; + zend_ulong num_key; int tmp_len = 0; MEMC_METHOD_INIT_VARS; @@ -1918,10 +1873,6 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool zval s_zvalue; zval *value = NULL; zend_long expiration = 0; - zend_string *payload = NULL; - uint32_t flags = 0; - uint32_t retry = 0; - memcached_return status; MEMC_METHOD_INIT_VARS; if (by_key) { @@ -2314,15 +2265,15 @@ PHP_METHOD(Memcached, addServer) s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x01000002 - if (host->val[0] == '/') { /* unix domain socket */ - status = memcached_server_add_unix_socket_with_weight(intern->memc, host->val, weight); + if (ZSTR_VAL(host)[0] == '/') { /* unix domain socket */ + status = memcached_server_add_unix_socket_with_weight(intern->memc, ZSTR_VAL(host), weight); } else if (memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_USE_UDP)) { - status = memcached_server_add_udp_with_weight(intern->memc, host->val, port, weight); + status = memcached_server_add_udp_with_weight(intern->memc, ZSTR_VAL(host), port, weight); } else { - status = memcached_server_add_with_weight(intern->memc, host->val, port, weight); + status = memcached_server_add_with_weight(intern->memc, ZSTR_VAL(host), port, weight); } #else - status = memcached_server_add_with_weight(intern->memc, host->val, port, weight); + status = memcached_server_add_with_weight(intern->memc, ZSTR_VAL(host), port, weight); #endif if (s_memc_status_handle_result_code(intern, status) == FAILURE) { @@ -2409,7 +2360,7 @@ PHP_METHOD(Memcached, addServers) } i++; /* catch-all for all errors */ - php_error_docref(NULL, E_WARNING, "could not add entry #%d to the server list", i+1); + php_error_docref(NULL, E_WARNING, "could not add entry #%d to the server list", i + 1); } ZEND_HASH_FOREACH_END(); status = memcached_server_push(intern->memc, list); From 513c091a67539efbd8f9ade7c9bb7c6815fe95c1 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Sat, 23 Jul 2016 20:13:36 +0800 Subject: [PATCH 092/104] Fixed locale_float.phpt test --- tests/experimental/locale_float.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/experimental/locale_float.phpt b/tests/experimental/locale_float.phpt index 9c512124..c071d974 100644 --- a/tests/experimental/locale_float.phpt +++ b/tests/experimental/locale_float.phpt @@ -9,7 +9,7 @@ if (!setlocale(LC_NUMERIC, "fi_FI", 'sv_SV', 'nl_NL')) { --FILE-- Date: Sat, 23 Jul 2016 20:32:06 +0800 Subject: [PATCH 093/104] Fixed OOM (tests/experimental/locale_float.phpt) --- php_memcached.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index 2b543e73..907914f3 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -829,18 +829,18 @@ zend_bool s_compress_value (php_memc_compression_type compression_type, zend_str if (!compress_status) { php_error_docref(NULL, E_WARNING, "could not compress value"); - MEMC_VAL_DEL_FLAG(*flags, MEMC_VAL_COMPRESSED); efree (buffer); return 0; } /* This means the value was too small to be compressed, still a success */ if (compressed_size > (ZSTR_LEN(payload) * MEMC_G(compression_factor))) { - MEMC_VAL_DEL_FLAG(*flags, MEMC_VAL_COMPRESSED); efree (buffer); return 1; } + MEMC_VAL_SET_FLAG(*flags, MEMC_VAL_COMPRESSED); + payload = zend_string_realloc(payload, compressed_size + sizeof(uint32_t), 0); /* Copy the uin32_t at the beginning */ @@ -1005,7 +1005,6 @@ zend_string *s_zval_to_payload(php_memc_object_t *intern, zval *value, uint32_t zend_string_release(payload); return NULL; } - MEMC_VAL_SET_FLAG(*flags, MEMC_VAL_COMPRESSED); } if (memc_user_data->set_udf_flags >= 0) { From 6837d894944a488ecd2b15d2e700e6183fcc4d2e Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Sat, 23 Jul 2016 20:44:03 +0800 Subject: [PATCH 094/104] Fixed test (tests/experimental/setmulti_badserialize.phpt) --- php_memcached.c | 2 +- tests/experimental/setmulti_badserialize.phpt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index 907914f3..0d208819 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -1786,7 +1786,7 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke } if (!s_memc_write_zval (intern, MEMC_OP_SET, server_key, str_key, value, expiration)) { - php_error_docref(NULL, E_WARNING, "failed to set key %s", str_key->val); + php_error_docref(NULL, E_WARNING, "failed to set key %s", ZSTR_VAL(str_key)); } if (!skey) { diff --git a/tests/experimental/setmulti_badserialize.phpt b/tests/experimental/setmulti_badserialize.phpt index 5081eedc..3bba314a 100644 --- a/tests/experimental/setmulti_badserialize.phpt +++ b/tests/experimental/setmulti_badserialize.phpt @@ -42,6 +42,6 @@ try { var_dump($m->getByKey('kef', 'foo')); --EXPECT-- - +Memcached::setMultiByKey(): failed to set key foo 1234 int(10) From f73befd69c2ff79456c0b9e2515e4f7c7172afa7 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Sat, 23 Jul 2016 22:35:13 +0800 Subject: [PATCH 095/104] Use zend_string_equals_literal --- php_memcached.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index 0d208819..e1d9d837 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -442,13 +442,13 @@ char *php_memc_printable_func (zend_fcall_info *fci, zend_fcall_info_cache *fci_ char *buffer = NULL; if (fci->object) { - spprintf (&buffer, 0, "%s::%s", fci->object->ce->name->val, fci_cache->function_handler->common.function_name); + spprintf (&buffer, 0, "%s::%s", ZSTR_VAL(fci->object->ce->name), fci_cache->function_handler->common.function_name); } else { if (Z_TYPE (fci->function_name) == IS_OBJECT) { - spprintf (&buffer, 0, "%s", Z_OBJCE (fci->function_name)->name->val); + spprintf (&buffer, 0, "%s", ZSTR_VAL(Z_OBJCE(fci->function_name)->name)); } else { - spprintf (&buffer, 0, "%s", Z_STRVAL (fci->function_name)); + spprintf (&buffer, 0, "%s", Z_STRVAL(fci->function_name)); } } return buffer; @@ -1156,7 +1156,7 @@ static PHP_METHOD(Memcached, __construct) zend_resource *le; plist_key = zend_string_alloc(sizeof("memcached:id=") + persistent_id->len - 1, 0); - snprintf(plist_key->val, plist_key->len + 1, "memcached:id=%s", persistent_id->val); + snprintf(ZSTR_VAL(plist_key), plist_key->len + 1, "memcached:id=%s", ZSTR_VAL(persistent_id)); if ((le = zend_hash_find_ptr(&EG(persistent_list), plist_key)) != NULL) { if (le->type == php_memc_list_entry()) { @@ -1170,7 +1170,7 @@ static PHP_METHOD(Memcached, __construct) } if (conn_str && conn_str->len > 0) { - intern->memc = memcached (conn_str->val, conn_str->len); + intern->memc = memcached (ZSTR_VAL(conn_str), ZSTR_LEN(conn_str)); } else { intern->memc = memcached (NULL, 0); @@ -1249,7 +1249,7 @@ static PHP_METHOD(Memcached, __construct) GC_REFCOUNT(&le) = 1; /* plist_key is not a persistent allocated key, thus we use str_update here */ - if (zend_hash_str_update_mem(&EG(persistent_list), plist_key->val, plist_key->len, &le, sizeof(le)) == NULL) { + if (zend_hash_str_update_mem(&EG(persistent_list), ZSTR_VAL(plist_key), ZSTR_LEN(plist_key), &le, sizeof(le)) == NULL) { zend_string_release(plist_key); php_error_docref(NULL, E_ERROR, "could not register persistent entry"); /* not reached */ @@ -3131,7 +3131,7 @@ static PHP_METHOD(Memcached, setSaslAuthData) RETURN_FALSE; } memc_user_data->has_sasl_data = 1; - status = memcached_set_sasl_auth_data(intern->memc, user->val, pass->val); + status = memcached_set_sasl_auth_data(intern->memc, ZSTR_VAL(user), ZSTR_VAL(pass)); if (s_memc_status_handle_result_code(intern, status) == FAILURE) { RETURN_FALSE; @@ -3503,28 +3503,28 @@ zend_bool s_memcached_result_to_zval(memcached_st *memc, memcached_result_st *re break; case MEMC_VAL_IS_LONG: - ZVAL_LONG(return_value, strtol(data->val, NULL, 10)); + ZVAL_LONG(return_value, strtol(ZSTR_VAL(data), NULL, 10)); break; case MEMC_VAL_IS_DOUBLE: { - if (payload_len == 8 && memcmp(data->val, "Infinity", 8) == 0) { + if (zend_string_equals_literal(data, "Infinity")) { ZVAL_DOUBLE(return_value, php_get_inf()); } - else if (payload_len == 9 && memcmp(data->val, "-Infinity", 9) == 0) { + else if (zend_string_equals_literal(data, "-Infinity")) { ZVAL_DOUBLE(return_value, -php_get_inf()); } - else if (payload_len == 3 && memcmp(data->val, "NaN", 3) == 0) { + else if (zend_string_equals_literal(data, "NaN")) { ZVAL_DOUBLE(return_value, php_get_nan()); } else { - ZVAL_DOUBLE(return_value, zend_strtod(data->val, NULL)); + ZVAL_DOUBLE(return_value, zend_strtod(ZSTR_VAL(data), NULL)); } } break; case MEMC_VAL_IS_BOOL: - ZVAL_BOOL(return_value, payload_len > 0 && data->val[0] == '1'); + ZVAL_BOOL(return_value, payload_len > 0 && ZSTR_VAL(data)[0] == '1'); break; case MEMC_VAL_IS_SERIALIZED: From 441168bebeab63b35813ded34c68d548bc3a1e4c Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Sun, 24 Jul 2016 12:37:29 +0800 Subject: [PATCH 096/104] avoided memory duplication --- php_memcached.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index e1d9d837..71b3c255 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -525,15 +525,14 @@ static void s_uint64_to_zval (zval *target, uint64_t value) { if (value >= ((uint64_t) LONG_MAX)) { - char *buffer; + zend_string *buffer; #ifdef PRIu64 - spprintf (&buffer, 0, "%" PRIu64, value); + buffer = strpprintf (0, "%" PRIu64, value); #else /* Best effort */ - spprintf (&buffer, 0, "%llu", value); + buffer = strpprintf (0, "%llu", value); #endif - ZVAL_STRING (target, buffer); - efree(buffer); + ZVAL_STR(target, buffer); } else { ZVAL_LONG (target, (zend_long) value); @@ -3331,28 +3330,28 @@ memcached_return s_server_cursor_list_servers_cb(const memcached_st *ptr, php_me static memcached_return s_server_cursor_version_cb(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context) { - char *address, *version; - size_t address_len, version_len; - - zval *return_value = (zval *) in_context; + zend_string *address, *version; + zval rv, *return_value = (zval *)in_context; #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x01000009 - version_len = spprintf(&version, sizeof(version), "%d.%d.%d", + version = strpprintf(0, "%d.%d.%d", memcached_server_major_version(instance), memcached_server_minor_version(instance), memcached_server_micro_version(instance)); #else - version_len = spprintf(&version, sizeof(version) - 1, "%d.%d.%d", + version = strpprintf(0, "%d.%d.%d", instance->major_version, instance->minor_version, instance->micro_version); #endif - address_len = spprintf(&address, 0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance) - 1); - add_assoc_stringl_ex(return_value, address, address_len, version, version_len); + address = strpprintf(0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance) - 1); + + ZVAL_STR(&rv, version); + zend_hash_add(Z_ARRVAL_P(return_value), address, &rv); + + zend_string_release(address); - efree(address); - efree(version); return MEMCACHED_SUCCESS; } From 5e42fa985b05cb1063a74a74ac14220d52652686 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Sun, 24 Jul 2016 12:41:53 +0800 Subject: [PATCH 097/104] Remove old version staff --- php_memcached.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index 71b3c255..f2cd38e3 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -3565,8 +3565,8 @@ zend_class_entry *php_memc_get_exception_base(int root) zval *pce_z; if ((pce_z = zend_hash_str_find(CG(class_table), - "runtimeexception", - sizeof("RuntimeException") - 1)) != NULL) { + "runtimeexception", + sizeof("RuntimeException") - 1)) != NULL) { pce = Z_CE_P(pce_z); spl_ce_RuntimeException = pce; return pce; @@ -3576,11 +3576,7 @@ zend_class_entry *php_memc_get_exception_base(int root) } } #endif -#if (PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION < 2) return zend_exception_get_default(); -#else - return zend_exception_get_default(); -#endif } From bb4556a38ce1fa87c088d05e8d7bf28792a794c8 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Mon, 25 Jul 2016 08:38:22 -0700 Subject: [PATCH 098/104] Partial fix build for memcached-protocl --- php_memcached.c | 56 +++++++++++++++++++++++------------------ php_memcached_private.h | 1 - 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index f2cd38e3..a7c1f42e 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -217,10 +217,20 @@ static inline php_memc_object_t *php_memc_fetch_object(zend_object *obj) { #ifdef HAVE_MEMCACHED_PROTOCOL typedef struct { - zend_object zo; php_memc_proto_handler_t *handler; + zend_object zo; } php_memc_server_t; +static inline php_memc_server_t *php_memc_server_fetch_object(zend_object *obj) { + return (php_memc_server_t *)((char *)obj - XtOffsetOf(php_memc_server_t, zo)); +} +#define Z_MEMC_SERVER_P(zv) php_memc_server_fetch_object(Z_OBJ_P(zv)) + +#ifdef ZTS +#define MEMC_SERVER_G(v) TSRMG(php_memcached_globals_id, zend_php_memcached_globals *, server.v) +#else +#define MEMC_SERVER_G(v) (php_memcached_globals.server.v) +#endif #endif static zend_class_entry *memcached_ce = NULL; @@ -3271,28 +3281,24 @@ zend_object *php_memc_object_new(zend_class_entry *ce) #ifdef HAVE_MEMCACHED_PROTOCOL static -void php_memc_server_free_storage(php_memc_server_t *intern) +void php_memc_server_free_storage(zend_object *object) { + php_memc_server_t *intern = php_memc_server_fetch_object(object); zend_object_std_dtor(&intern->zo); - efree (intern); } -zend_object_value php_memc_server_new(zend_class_entry *ce) +zend_object *php_memc_server_new(zend_class_entry *ce) { - zend_object_value retval; php_memc_server_t *intern; - zval *tmp; - intern = ecalloc(1, sizeof(php_memc_server_t)); + intern = ecalloc(1, sizeof(php_memc_server_t) + zend_object_properties_size(ce)); + zend_object_std_init(&intern->zo, ce); object_properties_init(&intern->zo, ce); - intern->handler = php_memc_proto_handler_new (); - - retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)php_memc_server_free_storage, NULL); - retval.handlers = &memcached_server_object_handlers; + intern->zo.handlers = &memcached_server_object_handlers; - return retval; + return &intern->zo; } #endif @@ -3587,8 +3593,8 @@ void s_destroy_cb (zend_fcall_info *fci) { if (fci->size > 0) { zval_ptr_dtor(&fci->function_name); - if (fci->object_ptr != NULL) { - zval_ptr_dtor(&fci->object_ptr); + if (fci->object) { + OBJ_RELEASE(fci->object); } } } @@ -3598,19 +3604,19 @@ PHP_METHOD(MemcachedServer, run) { int i; zend_bool rc; - zend *address; + zend_string *address; php_memc_server_t *intern; - intern = Z_MEMC_OBJ_P(getThis()); + intern = Z_MEMC_SERVER_P(getThis()); if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &address) == FAILURE) { return; } - rc = php_memc_proto_handler_run (intern->handler, address); + rc = php_memc_proto_handler_run(intern->handler, address); for (i = MEMC_SERVER_ON_MIN + 1; i < MEMC_SERVER_ON_MAX; i++) { - s_destroy_cb (&MEMC_G(server.callbacks) [i].fci); + s_destroy_cb(&MEMC_SERVER_G(callbacks) [i].fci); } RETURN_BOOL(rc); @@ -3633,14 +3639,14 @@ PHP_METHOD(MemcachedServer, on) } if (fci.size > 0) { - s_destroy_cb (&MEMC_G(server.callbacks) [event].fci); + s_destroy_cb (&MEMC_SERVER_G(callbacks) [event].fci); - MEMC_G(server.callbacks) [event].fci = fci; - MEMC_G(server.callbacks) [event].fci_cache = fci_cache; + MEMC_SERVER_G(callbacks) [event].fci = fci; + MEMC_SERVER_G(callbacks) [event].fci_cache = fci_cache; - Z_ADDREF_P (fci.function_name); - if (fci.object_ptr) { - Z_ADDREF_P (fci.object_ptr); + Z_TRY_ADDREF(fci.function_name); + if (fci.object) { + GC_REFCOUNT(fci.object)++; } } RETURN_BOOL(rc); @@ -4370,7 +4376,9 @@ PHP_MINIT_FUNCTION(memcached) #ifdef HAVE_MEMCACHED_PROTOCOL memcpy(&memcached_server_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + memcached_server_object_handlers.offset = XtOffsetOf(php_memc_server_t, zo); memcached_server_object_handlers.clone_obj = NULL; + memcached_server_object_handlers.free_obj = php_memc_server_free_storage; INIT_CLASS_ENTRY(ce, "MemcachedServer", memcached_server_class_methods); memcached_server_ce = zend_register_internal_class(&ce); diff --git a/php_memcached_private.h b/php_memcached_private.h index 329afc8d..c06bd626 100644 --- a/php_memcached_private.h +++ b/php_memcached_private.h @@ -195,7 +195,6 @@ ZEND_BEGIN_MODULE_GLOBALS(php_memcached) /* For deprecated values */ zend_long no_effect; - #ifdef HAVE_MEMCACHED_PROTOCOL struct { php_memc_server_cb_t callbacks [MEMC_SERVER_ON_MAX]; From 4d9fda94df531ea07753bba5744671c994619ad8 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Tue, 26 Jul 2016 14:54:59 +0800 Subject: [PATCH 099/104] use zval_copy --- php_memcached.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php_memcached.c b/php_memcached.c index f2cd38e3..e426f04c 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -1353,7 +1353,7 @@ zend_bool s_get_apply_fn(php_memc_object_t *intern, zend_string *key, zval *valu add_assoc_long (context->return_value, "flags", (zend_long) MEMC_VAL_GET_USER_FLAGS(flags)); } else { - ZVAL_ZVAL(context->return_value, value, 1, 0); + ZVAL_COPY(context->return_value, value); } return 0; /* Stop after one */ } From 56171da73e3d23f2728715abec261a97bfeed9c0 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Tue, 26 Jul 2016 17:07:14 +0800 Subject: [PATCH 100/104] Fixed bug fetch only fetched one result --- php_memcached.c | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index e426f04c..e7f73f31 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -382,7 +382,7 @@ static zend_bool s_invoke_cache_callback(zval *zobject, zend_fcall_info *fci, ze typedef zend_bool (*php_memc_result_apply_fn)(php_memc_object_t *intern, zend_string *key, zval *value, zval *cas, uint32_t flags, void *context); static -memcached_return php_memc_result_apply(php_memc_object_t *intern, php_memc_result_apply_fn result_apply_fn, void *context); +memcached_return php_memc_result_apply(php_memc_object_t *intern, php_memc_result_apply_fn result_apply_fn, zend_bool fetch_delay, void *context); static zend_bool php_memc_mget_apply(php_memc_object_t *intern, zend_string *server_key, @@ -579,7 +579,7 @@ uint64_t s_zval_to_uint64 (zval *cas) ****************************************/ static -memcached_return php_memc_result_apply(php_memc_object_t *intern, php_memc_result_apply_fn result_apply_fn, void *context) +memcached_return php_memc_result_apply(php_memc_object_t *intern, php_memc_result_apply_fn result_apply_fn, zend_bool fetch_delay, void *context) { memcached_result_st result, *result_ptr; memcached_return rc, status = MEMCACHED_SUCCESS; @@ -599,7 +599,7 @@ memcached_return php_memc_result_apply(php_memc_object_t *intern, php_memc_resul } else { zend_string *key; - zval zv_value, zv_cas; + zval val, zcas; zend_bool retval; uint64_t cas; @@ -608,7 +608,7 @@ memcached_return php_memc_result_apply(php_memc_object_t *intern, php_memc_resul const char *res_key; size_t res_key_len; - if (!s_memcached_result_to_zval(intern->memc, &result, &zv_value)) { + if (!s_memcached_result_to_zval(intern->memc, &result, &val)) { if (EG(exception)) { status = MEMC_RES_PAYLOAD_FAILURE; memcached_quit(intern->memc); @@ -623,19 +623,21 @@ memcached_return php_memc_result_apply(php_memc_object_t *intern, php_memc_resul cas = memcached_result_cas(&result); flags = memcached_result_flags(&result); - s_uint64_to_zval(&zv_cas, cas); + s_uint64_to_zval(&zcas, cas); key = zend_string_init (res_key, res_key_len, 0); - retval = result_apply_fn(intern, key, &zv_value, &zv_cas, flags, context); + retval = result_apply_fn(intern, key, &val, &zcas, flags, context); - zend_string_release (key); - zval_ptr_dtor(&zv_value); - zval_ptr_dtor(&zv_cas); + zend_string_release(key); + zval_ptr_dtor(&val); + zval_ptr_dtor(&zcas); /* Stop iterating on false */ if (!retval) { - /* Make sure we clear our results */ - while (memcached_fetch_result(intern->memc, &result, &rc)) {} + if (!fetch_delay) { + /* Make sure we clear our results */ + while (memcached_fetch_result(intern->memc, &result, &rc)) {} + } break; } } @@ -692,7 +694,7 @@ zend_bool php_memc_mget_apply(php_memc_object_t *intern, zend_string *server_key return 1; } - status = php_memc_result_apply(intern, result_apply_fn, context); + status = php_memc_result_apply(intern, result_apply_fn, 0, context); if (s_memc_status_handle_result_code(intern, status) == FAILURE) { return 0; @@ -1543,8 +1545,11 @@ void s_create_result_array(zend_string *key, zval *value, zval *cas, uint32_t fl add_assoc_str_ex(return_value, ZEND_STRL("key"), zend_string_copy(key)); add_assoc_zval_ex(return_value, ZEND_STRL("value"), value); - add_assoc_zval_ex(return_value, ZEND_STRL("cas"), cas); - add_assoc_long_ex(return_value, ZEND_STRL("flags"), MEMC_VAL_GET_USER_FLAGS(flags)); + if (Z_LVAL_P(cas)) { + /* BC compatible */ + add_assoc_zval_ex(return_value, ZEND_STRL("cas"), cas); + add_assoc_long_ex(return_value, ZEND_STRL("flags"), MEMC_VAL_GET_USER_FLAGS(flags)); + } } static @@ -1648,7 +1653,7 @@ PHP_METHOD(Memcached, fetch) s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); array_init(return_value); - status = php_memc_result_apply(intern, s_fetch_apply, return_value); + status = php_memc_result_apply(intern, s_fetch_apply, 1, return_value); if (s_memc_status_handle_result_code(intern, status) == FAILURE) { zval_ptr_dtor(return_value); @@ -1685,7 +1690,7 @@ PHP_METHOD(Memcached, fetchAll) s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); array_init(return_value); - status = php_memc_result_apply(intern, s_fetch_all_apply, return_value); + status = php_memc_result_apply(intern, s_fetch_all_apply, 0, return_value); if (s_memc_status_handle_result_code(intern, status) == FAILURE) { zval_dtor(return_value); From 41b005fd0f8587f105f673ef3ab77bd31d1285cd Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Tue, 26 Jul 2016 17:48:00 +0800 Subject: [PATCH 101/104] Fixed test --- tests/experimental/cas_bykey.phpt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/experimental/cas_bykey.phpt b/tests/experimental/cas_bykey.phpt index f8c80fa5..0a9da94e 100644 --- a/tests/experimental/cas_bykey.phpt +++ b/tests/experimental/cas_bykey.phpt @@ -8,12 +8,12 @@ include dirname(dirname(__FILE__)) . '/config.inc'; $m = memc_get_instance (); $m->delete('cas_test'); -$cas_token = null; $m->setByKey('keffe', 'cas_test', 10); -$v = $m->getbyKey('keffe', 'cas_test', null, $cas_token); +$v = $m->getbyKey('keffe', 'cas_test', null, Memcached::GET_EXTENDED); -if (is_null($cas_token)) { +$cas_token = $v["cas"]; +if (empty($cas_token)) { echo "Null cas token for key: cas_test value: 10\n"; return; } From 4fa21116f1e32efa4a9ef2045d32950649e6a508 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Tue, 26 Jul 2016 19:11:54 +0800 Subject: [PATCH 102/104] Value pass to callback behavior consistently with get (GET_EXTENED return array) --- php_memcached.c | 57 +++++++++++++++++++------- tests/experimental/getmulti_bykey.phpt | 6 +-- 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/php_memcached.c b/php_memcached.c index a5dd979c..095366c4 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -386,7 +386,7 @@ static void php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key); /* Invoke PHP functions */ -static zend_bool s_invoke_cache_callback(zval *zobject, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string *key, zval *value); +static zend_bool s_invoke_cache_callback(zval *zobject, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_bool with_cas, zend_string *key, zval *value); /* Iterate result sets */ typedef zend_bool (*php_memc_result_apply_fn)(php_memc_object_t *intern, zend_string *key, zval *value, zval *cas, uint32_t flags, void *context); @@ -750,7 +750,7 @@ zend_bool s_invoke_new_instance_cb(zval *object, zend_fcall_info *fci, zend_fcal } static -zend_bool s_invoke_cache_callback(zval *zobject, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string *key, zval *value) +zend_bool s_invoke_cache_callback(zval *zobject, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_bool with_cas, zend_string *key, zval *value) { zend_bool status = 0; zval params[4]; @@ -759,21 +759,42 @@ zend_bool s_invoke_cache_callback(zval *zobject, zend_fcall_info *fci, zend_fcal /* Prepare params */ ZVAL_COPY(¶ms[0], zobject); - ZVAL_STR(¶ms[1], zend_string_copy(key)); /* key */ - ZVAL_NEW_REF(¶ms[2], value); /* value */ - ZVAL_NEW_EMPTY_REF(¶ms[3]); /* expiration */ - ZVAL_NULL(Z_REFVAL(params[3])); + ZVAL_STR_COPY(¶ms[1], key); /* key */ + ZVAL_NEW_REF(¶ms[2], value); /* value */ + + if (with_cas) { + fci->param_count = 3; + } else { + ZVAL_NEW_EMPTY_REF(¶ms[3]); /* expiration */ + ZVAL_NULL(Z_REFVAL(params[3])); + fci->param_count = 4; + } fci->retval = &retval; fci->params = params; - fci->param_count = 4; if (zend_call_function(fci, fcc) == SUCCESS) { if (zend_is_true(&retval)) { - time_t expiration = zval_get_long(Z_REFVAL(params[3])); - status = s_memc_write_zval (intern, MEMC_OP_SET, NULL, key, Z_REFVAL(params[2]), expiration); - /* memleak? zval_ptr_dtor(value); */ - ZVAL_COPY(value, Z_REFVAL(params[2])); + time_t expiration; + zval *val = Z_REFVAL(params[2]); + + if (with_cas) { + if (Z_TYPE_P(val) == IS_ARRAY) { + zval *rv = zend_hash_str_find(Z_ARRVAL_P(val), "value", sizeof("value") - 1); + if (rv) { + zval *cas = zend_hash_str_find(Z_ARRVAL_P(val), "cas", sizeof("cas") -1); + expiration = cas? Z_LVAL_P(cas) : 0; + status = s_memc_write_zval (intern, MEMC_OP_SET, NULL, key, rv, expiration); + } + /* memleak? zval_ptr_dtor(value); */ + ZVAL_COPY(value, val); + } + } else { + expiration = zval_get_long(Z_REFVAL(params[3])); + status = s_memc_write_zval (intern, MEMC_OP_SET, NULL, key, val, expiration); + /* memleak? zval_ptr_dtor(value); */ + ZVAL_COPY(value, val); + } } } else { @@ -783,7 +804,9 @@ zend_bool s_invoke_cache_callback(zval *zobject, zend_fcall_info *fci, zend_fcal zval_ptr_dtor(¶ms[0]); zval_ptr_dtor(¶ms[1]); zval_ptr_dtor(¶ms[2]); - zval_ptr_dtor(¶ms[3]); + if (!with_cas) { + zval_ptr_dtor(¶ms[3]); + } zval_ptr_dtor(&retval); return status; @@ -1408,7 +1431,7 @@ void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) if (!mget_status) { if (s_memc_status_has_result_code(intern, MEMCACHED_NOTFOUND) && fci.size > 0) { - status = s_invoke_cache_callback(object, &fci, &fcc, key, return_value); + status = s_invoke_cache_callback(object, &fci, &fcc, context.extended, key, return_value); if (!status) { zval_ptr_dtor(return_value); @@ -1488,9 +1511,15 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke } MEMC_METHOD_FETCH_OBJECT; - s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); array_init(return_value); + if (zend_hash_num_elements(Z_ARRVAL_P(keys)) == 0) { + /* BC compatible */ + s_memc_set_status(intern, MEMCACHED_NOTFOUND, 0); + return; + } + + s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); preserve_order = (flags & MEMC_GET_PRESERVE_ORDER); s_hash_to_keys(&keys_out, Z_ARRVAL_P(keys), preserve_order, return_value); diff --git a/tests/experimental/getmulti_bykey.phpt b/tests/experimental/getmulti_bykey.phpt index e4eb112c..3f7a6f78 100644 --- a/tests/experimental/getmulti_bykey.phpt +++ b/tests/experimental/getmulti_bykey.phpt @@ -11,12 +11,10 @@ $m->set('foo', 1, 10); $m->set('bar', 2, 10); $m->delete('baz'); -$cas = array(); -var_dump($m->getMultiByKey('foo', array('foo', 'bar', 'baz'), $cas, Memcached::GET_PRESERVE_ORDER)); +var_dump($m->getMultiByKey('foo', array('foo', 'bar', 'baz'), Memcached::GET_PRESERVE_ORDER)); echo $m->getResultMessage(), "\n"; -$cas = array(); -var_dump($m->getMultiByKey('foo', array(), $cas, Memcached::GET_PRESERVE_ORDER)); +var_dump($m->getMultiByKey('foo', array(), Memcached::GET_PRESERVE_ORDER)); echo $m->getResultMessage(), "\n"; --EXPECT-- From 35ef91129d1303bd7d5c7e742d27c08d35d5728c Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Mon, 8 Aug 2016 00:37:20 -0400 Subject: [PATCH 103/104] Igbinary php7 development is in igbinary/igbinary master branch now igbinary7 was moved to src/php7, and bug fixes/improvements were/will be added there later. See https://github.com/igbinary/igbinary/pull/62 --- .travis/travis.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis/travis.sh b/.travis/travis.sh index d43a15fc..264a7f3b 100755 --- a/.travis/travis.sh +++ b/.travis/travis.sh @@ -67,8 +67,8 @@ function install_libmemcached() { } function install_igbinary() { - git clone https://github.com/igbinary/igbinary7.git - pushd igbinary7 + git clone https://github.com/igbinary/igbinary.git + pushd igbinary phpize ./configure make From a9eb87408b03669a83672e5aa646f9ff668b4cfb Mon Sep 17 00:00:00 2001 From: Aaron Stone Date: Mon, 8 Aug 2016 11:37:31 -0700 Subject: [PATCH 104/104] Adjust the Travis CI matrix: PHP 5.5, 5.6, 7.0, fewer revisions of libmemcached --- .travis.yml | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index b2e113ef..3c018f3b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,21 +1,14 @@ language: php php: - 7.0 + - 5.6 + - 5.5 env: - - LIBMEMCACHED_VERSION=1.0.18 - - LIBMEMCACHED_VERSION=1.0.17 - - LIBMEMCACHED_VERSION=1.0.16 - - LIBMEMCACHED_VERSION=1.0.15 - - LIBMEMCACHED_VERSION=1.0.14 - - LIBMEMCACHED_VERSION=1.0.10 - - LIBMEMCACHED_VERSION=1.0.8 - - LIBMEMCACHED_VERSION=1.0.7 - - LIBMEMCACHED_VERSION=1.0.6 - - LIBMEMCACHED_VERSION=1.0.2 - #- LIBMEMCACHED_VERSION=0.53 - #- LIBMEMCACHED_VERSION=0.49 - #- LIBMEMCACHED_VERSION=0.44 + - LIBMEMCACHED_VERSION=1.0.18 # Debian Jessie / Ubuntu Xenial + - LIBMEMCACHED_VERSION=1.0.16 # RHEL / CentOS 7 + - LIBMEMCACHED_VERSION=1.0.8 # Debian Wheezy / Ubuntu Trusty + - LIBMEMCACHED_VERSION=0.44 # Ubuntu Precise addons: apt: packages: