Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/phpredis/phpredis.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'redis.c')
-rw-r--r--redis.c560
1 files changed, 326 insertions, 234 deletions
diff --git a/redis.c b/redis.c
index 6b283170..38a01142 100644
--- a/redis.c
+++ b/redis.c
@@ -72,8 +72,8 @@ PHP_INI_END()
ZEND_DECLARE_MODULE_GLOBALS(redis)
static zend_function_entry redis_functions[] = {
- PHP_ME(Redis, __construct, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Redis, __destruct, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Redis, __construct, NULL, ZEND_ACC_CTOR | ZEND_ACC_PUBLIC)
+ PHP_ME(Redis, __destruct, NULL, ZEND_ACC_DTOR | ZEND_ACC_PUBLIC)
PHP_ME(Redis, connect, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Redis, pconnect, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Redis, close, NULL, ZEND_ACC_PUBLIC)
@@ -237,6 +237,9 @@ static zend_function_entry redis_functions[] = {
/* config */
PHP_ME(Redis, config, NULL, ZEND_ACC_PUBLIC)
+ /* slowlog */
+ PHP_ME(Redis, slowlog, NULL, ZEND_ACC_PUBLIC)
+
/* introspection */
PHP_ME(Redis, getHost, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Redis, getPort, NULL, ZEND_ACC_PUBLIC)
@@ -394,6 +397,13 @@ PHPAPI int redis_sock_get(zval *id, RedisSock **redis_sock TSRMLS_DC, int no_thr
}
return -1;
}
+ if ((*redis_sock)->lazy_connect)
+ {
+ (*redis_sock)->lazy_connect = 0;
+ if (redis_sock_server_open(*redis_sock, 1 TSRMLS_CC) < 0) {
+ return -1;
+ }
+ }
return Z_LVAL_PP(socket);
}
@@ -629,18 +639,17 @@ PHPAPI int redis_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) {
}
/* if there is a redis sock already we have to remove it from the list */
- if (redis_sock_get(object, &redis_sock TSRMLS_CC, 0) > 0) {
+ if (redis_sock_get(object, &redis_sock TSRMLS_CC, 1) > 0) {
if (zend_hash_find(Z_OBJPROP_P(object), "socket",
- sizeof("socket"), (void **) &socket) == FAILURE) {
+ sizeof("socket"), (void **) &socket) == FAILURE)
+ {
/* maybe there is a socket but the id isn't known.. what to do? */
} else {
zend_list_delete(Z_LVAL_PP(socket)); /* the refcount should be decreased and the detructor called */
}
- } else {
- zend_clear_exception(TSRMLS_C); /* clear exception triggered by non-existent socket during connect(). */
}
- redis_sock = redis_sock_create(host, host_len, port, timeout, persistent, persistent_id, retry_interval);
+ redis_sock = redis_sock_create(host, host_len, port, timeout, persistent, persistent_id, retry_interval, 0);
if (redis_sock_server_open(redis_sock, 1 TSRMLS_CC) < 0) {
redis_free_socket(redis_sock);
@@ -802,43 +811,103 @@ PHP_METHOD(Redis, close)
}
/* }}} */
-/* {{{ proto boolean Redis::set(string key, mixed value)
- */
-PHP_METHOD(Redis, set)
-{
+/* {{{ proto boolean Redis::set(string key, mixed value, long timeout | array options) */
+PHP_METHOD(Redis, set) {
zval *object;
RedisSock *redis_sock;
- char *key = NULL, *val = NULL, *cmd;
+ char *key = NULL, *val = NULL, *cmd, *exp_type = NULL, *set_type = NULL;
int key_len, val_len, cmd_len;
long expire = -1;
int val_free = 0, key_free = 0;
- zval *z_value;
+ zval *z_value, *z_opts = NULL;
- if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Osz|l",
- &object, redis_ce, &key, &key_len,
- &z_value, &expire) == FAILURE) {
+ // Make sure the arguments are correct
+ if(zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Osz|z",
+ &object, redis_ce, &key, &key_len, &z_value,
+ &z_opts) == FAILURE)
+ {
RETURN_FALSE;
}
- if (redis_sock_get(object, &redis_sock TSRMLS_CC, 0) < 0) {
+ // Ensure we can grab our redis socket
+ if(redis_sock_get(object, &redis_sock TSRMLS_CC, 0) < 0) {
+ RETURN_FALSE;
+ }
+
+ /* Our optional argument can either be a long (to support legacy SETEX */
+ /* redirection), or an array with Redis >= 2.6.12 set options */
+ if(z_opts && Z_TYPE_P(z_opts) != IS_LONG && Z_TYPE_P(z_opts) != IS_ARRAY) {
RETURN_FALSE;
}
+ /* Serialization, key prefixing */
val_free = redis_serialize(redis_sock, z_value, &val, &val_len TSRMLS_CC);
- key_free = redis_key_prefix(redis_sock, &key, &key_len TSRMLS_CC);
- if(expire > 0) {
- cmd_len = redis_cmd_format_static(&cmd, "SETEX", "sds", key, key_len, expire, val, val_len);
+ key_free = redis_key_prefix(redis_sock, &key, &key_len TSRMLS_CC);
+
+ if(z_opts && Z_TYPE_P(z_opts) == IS_ARRAY) {
+ HashTable *kt = Z_ARRVAL_P(z_opts);
+ int type;
+ unsigned int ht_key_len;
+ unsigned long idx;
+ char *k;
+ zval **v;
+
+ /* Iterate our option array */
+ for(zend_hash_internal_pointer_reset(kt);
+ zend_hash_has_more_elements(kt) == SUCCESS;
+ zend_hash_move_forward(kt))
+ {
+ // Grab key and value
+ type = zend_hash_get_current_key_ex(kt, &k, &ht_key_len, &idx, 0, NULL);
+ zend_hash_get_current_data(kt, (void**)&v);
+
+ if(type == HASH_KEY_IS_STRING && (Z_TYPE_PP(v) == IS_LONG) &&
+ (Z_LVAL_PP(v) > 0) && IS_EX_PX_ARG(k))
+ {
+ exp_type = k;
+ expire = Z_LVAL_PP(v);
+ } else if(Z_TYPE_PP(v) == IS_STRING && IS_NX_XX_ARG(Z_STRVAL_PP(v))) {
+ set_type = Z_STRVAL_PP(v);
+ }
+ }
+ } else if(z_opts && Z_TYPE_P(z_opts) == IS_LONG) {
+ expire = Z_LVAL_P(z_opts);
+ }
+
+ /* Now let's construct the command we want */
+ if(exp_type && set_type) {
+ /* SET <key> <value> NX|XX PX|EX <timeout> */
+ cmd_len = redis_cmd_format_static(&cmd, "SET", "ssssl", key, key_len,
+ val, val_len, set_type, 2, exp_type,
+ 2, expire);
+ } else if(exp_type) {
+ /* SET <key> <value> PX|EX <timeout> */
+ cmd_len = redis_cmd_format_static(&cmd, "SET", "sssl", key, key_len,
+ val, val_len, exp_type, 2, expire);
+ } else if(set_type) {
+ /* SET <key> <value> NX|XX */
+ cmd_len = redis_cmd_format_static(&cmd, "SET", "sss", key, key_len,
+ val, val_len, set_type, 2);
+ } else if(expire > 0) {
+ /* Backward compatible SETEX redirection */
+ cmd_len = redis_cmd_format_static(&cmd, "SETEX", "sds", key, key_len,
+ expire, val, val_len);
} else {
- cmd_len = redis_cmd_format_static(&cmd, "SET", "ss", key, key_len, val, val_len);
+ /* SET <key> <value> */
+ cmd_len = redis_cmd_format_static(&cmd, "SET", "ss", key, key_len,
+ val, val_len);
}
- if(val_free) efree(val);
+
+ /* Free our key or value if we prefixed/serialized */
if(key_free) efree(key);
+ if(val_free) efree(val);
- REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len);
- IF_ATOMIC() {
- redis_boolean_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL, NULL);
- }
- REDIS_PROCESS_RESPONSE(redis_boolean_response);
+ /* Kick off the command */
+ REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len);
+ IF_ATOMIC() {
+ redis_boolean_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL, NULL);
+ }
+ REDIS_PROCESS_RESPONSE(redis_boolean_response);
}
PHPAPI void redis_generic_setex(INTERNAL_FUNCTION_PARAMETERS, char *keyword) {
@@ -1323,88 +1392,85 @@ PHP_METHOD(Redis, decrBy){
*/
PHP_METHOD(Redis, getMultiple)
{
- zval *object, *array, **data;
- HashTable *arr_hash;
- HashPosition pointer;
+ zval *object, *z_args, **z_ele;
+ HashTable *hash;
+ HashPosition ptr;
RedisSock *redis_sock;
- char *cmd = "", *old_cmd = NULL;
- int cmd_len = 0, array_count, elements = 1;
+ smart_str cmd = {0};
+ int arg_count;
- if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oa",
- &object, redis_ce, &array) == FAILURE) {
+ // Make sure we have proper arguments
+ if(zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oa",
+ &object, redis_ce, &z_args) == FAILURE) {
RETURN_FALSE;
}
- if (redis_sock_get(object, &redis_sock TSRMLS_CC, 0) < 0) {
+ // We'll need the socket
+ if(redis_sock_get(object, &redis_sock TSRMLS_CC, 0) < 0) {
RETURN_FALSE;
}
- arr_hash = Z_ARRVAL_P(array);
- array_count = zend_hash_num_elements(arr_hash);
+ // Grab our array
+ hash = Z_ARRVAL_P(z_args);
- if (array_count == 0) {
+ // We don't need to do anything if there aren't any keys
+ if((arg_count = zend_hash_num_elements(hash)) == 0) {
RETURN_FALSE;
}
- for (zend_hash_internal_pointer_reset_ex(arr_hash, &pointer);
- zend_hash_get_current_data_ex(arr_hash, (void**) &data,
- &pointer) == SUCCESS;
- zend_hash_move_forward_ex(arr_hash, &pointer)) {
+ // Build our command header
+ redis_cmd_init_sstr(&cmd, arg_count, "MGET", 4);
+ // Iterate through and grab our keys
+ for(zend_hash_internal_pointer_reset_ex(hash, &ptr);
+ zend_hash_get_current_data_ex(hash, (void**)&z_ele, &ptr) == SUCCESS;
+ zend_hash_move_forward_ex(hash, &ptr))
+ {
char *key;
- int key_len;
+ int key_len, key_free;
zval *z_tmp = NULL;
- char *old_cmd;
- int key_free;
- if (Z_TYPE_PP(data) == IS_STRING) {
- key = Z_STRVAL_PP(data);
- key_len = Z_STRLEN_PP(data);
- } else { /* not a string, copy and convert. */
+ // If the key isn't a string, turn it into one
+ if(Z_TYPE_PP(z_ele) == IS_STRING) {
+ key = Z_STRVAL_PP(z_ele);
+ key_len = Z_STRLEN_PP(z_ele);
+ } else {
MAKE_STD_ZVAL(z_tmp);
- *z_tmp = **data;
+ *z_tmp = **z_ele;
zval_copy_ctor(z_tmp);
convert_to_string(z_tmp);
key = Z_STRVAL_P(z_tmp);
key_len = Z_STRLEN_P(z_tmp);
}
- old_cmd = NULL;
- if(*cmd) {
- old_cmd = cmd;
- }
- key_free = redis_key_prefix(redis_sock, &key, &key_len TSRMLS_CC);
- cmd_len = redis_cmd_format(&cmd, "%s$%d" _NL "%s" _NL
- , cmd, cmd_len
- , key_len, key, key_len);
- if(key_free) efree(key);
+ // Apply key prefix if necissary
+ key_free = redis_key_prefix(redis_sock, &key, &key_len TSRMLS_CC);
- if(old_cmd) {
- efree(old_cmd);
- }
- elements++;
+ // Append this key to our command
+ redis_cmd_append_sstr(&cmd, key, key_len);
+
+ // Free our key if it was prefixed
+ if(key_free) efree(key);
+
+ // Free oour temporary ZVAL if we converted from a non-string
if(z_tmp) {
zval_dtor(z_tmp);
efree(z_tmp);
+ z_tmp = NULL;
}
}
- old_cmd = cmd;
- cmd_len = redis_cmd_format(&cmd, "*%d" _NL "$4" _NL "MGET" _NL "%s", elements, cmd, cmd_len);
- efree(old_cmd);
-
- REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len);
+ // Kick off our command
+ REDIS_PROCESS_REQUEST(redis_sock, cmd.c, cmd.len);
IF_ATOMIC() {
- if (redis_sock_read_multibulk_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU,
- redis_sock, NULL, NULL) < 0) {
- RETURN_FALSE;
- }
+ if(redis_sock_read_multibulk_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU,
+ redis_sock, NULL, NULL) < 0) {
+ RETURN_FALSE;
+ }
}
REDIS_PROCESS_RESPONSE(redis_sock_read_multibulk_reply);
-
}
-/* }}} */
/* {{{ proto boolean Redis::exists(string key)
*/
@@ -2360,7 +2426,6 @@ PHP_METHOD(Redis, sMembers)
}
/* }}} */
-
PHPAPI int generic_multiple_args_cmd(INTERNAL_FUNCTION_PARAMETERS, char *keyword, int keyword_len,
int min_argc, RedisSock **out_sock, int has_timeout, int all_keys, int can_serialize)
{
@@ -4290,187 +4355,167 @@ PHP_METHOD(Redis, zIncrBy)
generic_incrby_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, "ZINCRBY", sizeof("ZINCRBY")-1);
}
/* }}} */
-PHPAPI void generic_z_command(INTERNAL_FUNCTION_PARAMETERS, char *command, int command_len) {
-
- zval *object, *keys_array, *weights_array = NULL, **data;
- HashTable *arr_weights_hash = NULL, *arr_keys_hash;
- int key_output_len, array_weights_count, array_keys_count, operation_len = 0;
- char *key_output, *operation;
- RedisSock *redis_sock;
- HashPosition pointer;
- char *cmd = "";
- char *old_cmd;
- int cmd_len, cmd_elements;
- int free_key_output;
-
- if(zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Osa|as",
- &object, redis_ce,
- &key_output, &key_output_len, &keys_array, &weights_array, &operation, &operation_len) == FAILURE) {
- RETURN_FALSE;
- }
+PHPAPI void generic_z_command(INTERNAL_FUNCTION_PARAMETERS, char *command, int command_len) {
+ zval *object, *z_keys, *z_weights = NULL, **z_data;
+ HashTable *ht_keys, *ht_weights = NULL;
+ RedisSock *redis_sock;
+ smart_str cmd = {0};
+ HashPosition ptr;
+ char *store_key, *agg_op = NULL;
+ int cmd_arg_count = 2, store_key_len, agg_op_len = 0, keys_count;
+
+ // Grab our parameters
+ if(zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Osa|a!s",
+ &object, redis_ce, &store_key, &store_key_len,
+ &z_keys, &z_weights, &agg_op, &agg_op_len) == FAILURE)
+ {
+ RETURN_FALSE;
+ }
+ // We'll need our socket
if(redis_sock_get(object, &redis_sock TSRMLS_CC, 0) < 0) {
- RETURN_FALSE;
+ RETURN_FALSE;
}
- arr_keys_hash = Z_ARRVAL_P(keys_array);
- array_keys_count = zend_hash_num_elements(arr_keys_hash);
+ // Grab our keys argument as an array
+ ht_keys = Z_ARRVAL_P(z_keys);
- if (array_keys_count == 0) {
+ // Nothing to do if there aren't any keys
+ if((keys_count = zend_hash_num_elements(ht_keys)) == 0) {
RETURN_FALSE;
+ } else {
+ // Increment our overall argument count
+ cmd_arg_count += keys_count;
}
- if(weights_array != NULL) {
- arr_weights_hash = Z_ARRVAL_P(weights_array);
- array_weights_count = zend_hash_num_elements(arr_weights_hash);
- if (array_weights_count == 0) {
- RETURN_FALSE;
- }
- if((array_weights_count != 0) && (array_weights_count != array_keys_count)) {
- RETURN_FALSE;
- }
+ // Grab and validate our weights array
+ if(z_weights != NULL) {
+ ht_weights = Z_ARRVAL_P(z_weights);
- }
+ // This command is invalid if the weights array isn't the same size
+ // as our keys array.
+ if(zend_hash_num_elements(ht_weights) != keys_count) {
+ RETURN_FALSE;
+ }
- free_key_output = redis_key_prefix(redis_sock, &key_output, &key_output_len TSRMLS_CC);
- cmd_elements = 3;
- cmd_len = redis_cmd_format(&cmd,
- "$%d" _NL /* command_len */
- "%s" _NL /* command */
+ // Increment our overall argument count by the number of keys
+ // plus one, for the "WEIGHTS" argument itself
+ cmd_arg_count += keys_count + 1;
+ }
- "$%d" _NL /* key_output_len */
- "%s" _NL /* key_output */
+ // AGGREGATE option
+ if(agg_op_len != 0) {
+ // Verify our aggregation option
+ if(strncasecmp(agg_op, "SUM", sizeof("SUM")) &&
+ strncasecmp(agg_op, "MIN", sizeof("MIN")) &&
+ strncasecmp(agg_op, "MAX", sizeof("MAX")))
+ {
+ RETURN_FALSE;
+ }
- "$%d" _NL
- "%d" _NL /* array_keys_count */
+ // Two more arguments: "AGGREGATE" and agg_op
+ cmd_arg_count += 2;
+ }
- , command_len, command, command_len
- , key_output_len, key_output, key_output_len
- , integer_length(array_keys_count), array_keys_count);
- if(free_key_output) efree(key_output);
+ // Command header
+ redis_cmd_init_sstr(&cmd, cmd_arg_count, command, command_len);
- /* keys */
- for (zend_hash_internal_pointer_reset_ex(arr_keys_hash, &pointer);
- zend_hash_get_current_data_ex(arr_keys_hash, (void**) &data,
- &pointer) == SUCCESS;
- zend_hash_move_forward_ex(arr_keys_hash, &pointer)) {
+ // Prefix our key if necessary and add the output key
+ int key_free = redis_key_prefix(redis_sock, &store_key, &store_key_len TSRMLS_CC);
+ redis_cmd_append_sstr(&cmd, store_key, store_key_len);
+ if(key_free) efree(store_key);
- if (Z_TYPE_PP(data) == IS_STRING) {
- char *old_cmd = NULL;
- char *data_str;
- int data_len;
- int free_data;
-
- if(*cmd) {
- old_cmd = cmd;
- }
- data_str = Z_STRVAL_PP(data);
- data_len = Z_STRLEN_PP(data);
-
- free_data = redis_key_prefix(redis_sock, &data_str, &data_len TSRMLS_CC);
- cmd_len = redis_cmd_format(&cmd,
- "%s" /* cmd */
- "$%d" _NL
- "%s" _NL
- , cmd, cmd_len
- , data_len, data_str, data_len);
- cmd_elements++;
- if(free_data) efree(data_str);
- if(old_cmd) {
- efree(old_cmd);
- }
+ // Number of input keys argument
+ redis_cmd_append_sstr_int(&cmd, keys_count);
+
+ // Process input keys
+ for(zend_hash_internal_pointer_reset_ex(ht_keys, &ptr);
+ zend_hash_get_current_data_ex(ht_keys, (void**)&z_data, &ptr)==SUCCESS;
+ zend_hash_move_forward_ex(ht_keys, &ptr))
+ {
+ char *key;
+ int key_free, key_len;
+ zval *z_tmp = NULL;
+
+ if(Z_TYPE_PP(z_data) == IS_STRING) {
+ key = Z_STRVAL_PP(z_data);
+ key_len = Z_STRLEN_PP(z_data);
+ } else {
+ MAKE_STD_ZVAL(z_tmp);
+ *z_tmp = **z_data;
+ convert_to_string(z_tmp);
+
+ key = Z_STRVAL_P(z_tmp);
+ key_len = Z_STRLEN_P(z_tmp);
}
- }
- /* weight */
- if(weights_array != NULL) {
- cmd_len = redis_cmd_format(&cmd,
- "%s" /* cmd */
- "$7" _NL
- "WEIGHTS" _NL
- , cmd, cmd_len);
- cmd_elements++;
-
- for (zend_hash_internal_pointer_reset_ex(arr_weights_hash, &pointer);
- zend_hash_get_current_data_ex(arr_weights_hash, (void**) &data, &pointer) == SUCCESS;
- zend_hash_move_forward_ex(arr_weights_hash, &pointer)) {
-
- // Ignore non numeric arguments, unless they're the special Redis numbers
- // "inf" ,"-inf", and "+inf" which can be passed as weights
- if (Z_TYPE_PP(data) != IS_LONG && Z_TYPE_PP(data) != IS_DOUBLE &&
- strncasecmp(Z_STRVAL_PP(data), "inf", sizeof("inf")) != 0 &&
- strncasecmp(Z_STRVAL_PP(data), "-inf", sizeof("-inf")) != 0 &&
- strncasecmp(Z_STRVAL_PP(data), "+inf", sizeof("+inf")) != 0)
- {
- continue;
- }
+ // Apply key prefix if necessary
+ key_free = redis_key_prefix(redis_sock, &key, &key_len TSRMLS_CC);
- old_cmd = NULL;
- if(*cmd) {
- old_cmd = cmd;
- }
+ // Append this input set
+ redis_cmd_append_sstr(&cmd, key, key_len);
- if(Z_TYPE_PP(data) == IS_LONG) {
- cmd_len = redis_cmd_format(&cmd,
- "%s" /* cmd */
- "$%d" _NL /* data_len */
- "%d" _NL /* data */
- , cmd, cmd_len
- , integer_length(Z_LVAL_PP(data)), Z_LVAL_PP(data));
-
- } else if(Z_TYPE_PP(data) == IS_DOUBLE) {
- cmd_len = redis_cmd_format(&cmd,
- "%s" /* cmd */
- "$%f" _NL /* data, including size */
- , cmd, cmd_len
- , Z_DVAL_PP(data));
- } else if(Z_TYPE_PP(data) == IS_STRING) {
- cmd_len = redis_cmd_format(&cmd,
- "%s" /* cmd */
- "$%d" _NL /* data len */
- "%s" _NL /* data */
- , cmd, cmd_len, Z_STRLEN_PP(data),
- Z_STRVAL_PP(data), Z_STRLEN_PP(data));
- }
+ // Free our key if it was prefixed
+ if(key_free) efree(key);
- // keep track of elements added
- cmd_elements++;
- if(old_cmd) {
- efree(old_cmd);
- }
- }
- }
+ // Free our temporary z_val if it was converted
+ if(z_tmp) {
+ zval_dtor(z_tmp);
+ efree(z_tmp);
+ z_tmp = NULL;
+ }
+ }
- if(operation_len != 0) {
- char *old_cmd = NULL;
- old_cmd = cmd;
- cmd_len = redis_cmd_format(&cmd,
- "%s" /* cmd */
- "$9" _NL
- "AGGREGATE" _NL
- "$%d" _NL
- "%s" _NL
- , cmd, cmd_len
- , operation_len, operation, operation_len);
- cmd_elements += 2;
- efree(old_cmd);
- }
+ // Weights
+ if(ht_weights != NULL) {
+ // Append "WEIGHTS" argument
+ redis_cmd_append_sstr(&cmd, "WEIGHTS", sizeof("WEIGHTS") - 1);
+
+ // Process weights
+ for(zend_hash_internal_pointer_reset_ex(ht_weights, &ptr);
+ zend_hash_get_current_data_ex(ht_weights, (void**)&z_data, &ptr)==SUCCESS;
+ zend_hash_move_forward_ex(ht_weights, &ptr))
+ {
+ // Ignore non numeric arguments, unless they're special Redis numbers
+ if (Z_TYPE_PP(z_data) != IS_LONG && Z_TYPE_PP(z_data) != IS_DOUBLE &&
+ strncasecmp(Z_STRVAL_PP(z_data), "inf", sizeof("inf")) != 0 &&
+ strncasecmp(Z_STRVAL_PP(z_data), "-inf", sizeof("-inf")) != 0 &&
+ strncasecmp(Z_STRVAL_PP(z_data), "+inf", sizeof("+inf")) != 0)
+ {
+ // We should abort if we have an invalid weight, rather than pass
+ // a different number of weights than the user is expecting
+ efree(cmd.c);
+ RETURN_FALSE;
+ }
- old_cmd = cmd;
- cmd_len = redis_cmd_format(&cmd,
- "*%d" _NL
- "%s"
- , cmd_elements
- , cmd, cmd_len);
- efree(old_cmd);
+ // Append the weight based on the input type
+ switch(Z_TYPE_PP(z_data)) {
+ case IS_LONG:
+ redis_cmd_append_sstr_long(&cmd, Z_LVAL_PP(z_data));
+ break;
+ case IS_DOUBLE:
+ redis_cmd_append_sstr_dbl(&cmd, Z_DVAL_PP(z_data));
+ break;
+ case IS_STRING:
+ redis_cmd_append_sstr(&cmd, Z_STRVAL_PP(z_data), Z_STRLEN_PP(z_data));
+ break;
+ }
+ }
+ }
- REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len);
- IF_ATOMIC() {
- redis_long_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL, NULL);
- }
- REDIS_PROCESS_RESPONSE(redis_long_response);
+ // Aggregation options, if we have them
+ if(agg_op_len != 0) {
+ redis_cmd_append_sstr(&cmd, "AGGREGATE", sizeof("AGGREGATE") - 1);
+ redis_cmd_append_sstr(&cmd, agg_op, agg_op_len);
+ }
+ // Kick off our request
+ REDIS_PROCESS_REQUEST(redis_sock, cmd.c, cmd.len);
+ IF_ATOMIC() {
+ redis_long_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL, NULL);
+ }
+ REDIS_PROCESS_RESPONSE(redis_long_response);
}
/* zInter */
@@ -5885,6 +5930,56 @@ PHP_METHOD(Redis, config)
/* }}} */
+/* {{{ proto boolean Redis::slowlog(string arg, [int option])
+ */
+PHP_METHOD(Redis, slowlog) {
+ zval *object;
+ RedisSock *redis_sock;
+ char *arg, *cmd;
+ int arg_len, cmd_len;
+ long option;
+ enum {SLOWLOG_GET, SLOWLOG_LEN, SLOWLOG_RESET} mode;
+
+ // Make sure we can get parameters
+ if(zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os|l",
+ &object, redis_ce, &arg, &arg_len, &option) == FAILURE)
+ {
+ RETURN_FALSE;
+ }
+
+ // Figure out what kind of slowlog command we're executing
+ if(!strncasecmp(arg, "GET", 3)) {
+ mode = SLOWLOG_GET;
+ } else if(!strncasecmp(arg, "LEN", 3)) {
+ mode = SLOWLOG_LEN;
+ } else if(!strncasecmp(arg, "RESET", 5)) {
+ mode = SLOWLOG_RESET;
+ } else {
+ // This command is not valid
+ RETURN_FALSE;
+ }
+
+ // Make sure we can grab our redis socket
+ if(redis_sock_get(object, &redis_sock TSRMLS_CC, 0) < 0) {
+ RETURN_FALSE;
+ }
+
+ // Create our command. For everything except SLOWLOG GET (with an arg) it's just two parts
+ if(mode == SLOWLOG_GET && ZEND_NUM_ARGS() == 2) {
+ cmd_len = redis_cmd_format_static(&cmd, "SLOWLOG", "sl", arg, arg_len, option);
+ } else {
+ cmd_len = redis_cmd_format_static(&cmd, "SLOWLOG", "s", arg, arg_len);
+ }
+
+ // Kick off our command
+ REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len);
+ IF_ATOMIC() {
+ if(redis_read_variant_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL) < 0) {
+ RETURN_FALSE;
+ }
+ }
+ REDIS_PROCESS_RESPONSE(redis_read_variant_reply);
+}
// Construct an EVAL or EVALSHA command, with option argument array and number of arguments that are keys parameter
PHPAPI int
@@ -6511,9 +6606,6 @@ PHP_METHOD(Redis, client) {
cmd_len = redis_cmd_format_static(&cmd, "CLIENT", "s", opt, opt_len);
}
- // Handle CLIENT LIST specifically
- int is_list = !strncasecmp(opt, "list", 4);
-
// Execute our queue command
REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len);