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:
-rw-r--r--php_redis.h2
-rw-r--r--redis.c50
-rw-r--r--redis_cluster.c111
-rw-r--r--redis_cluster.h1
-rw-r--r--redis_commands.c49
-rw-r--r--redis_commands.h8
6 files changed, 184 insertions, 37 deletions
diff --git a/php_redis.h b/php_redis.h
index 078d3ec5..aa621f18 100644
--- a/php_redis.h
+++ b/php_redis.h
@@ -197,6 +197,7 @@ PHP_METHOD(Redis, wait);
PHP_METHOD(Redis, pubsub);
PHP_METHOD(Redis, client);
+PHP_METHOD(Redis, command);
PHP_METHOD(Redis, rawcommand);
/* SCAN and friends */
@@ -220,7 +221,6 @@ PHP_METHOD(Redis, isConnected);
PHP_METHOD(Redis, getPersistentID);
PHP_METHOD(Redis, getAuth);
PHP_METHOD(Redis, getMode);
-PHP_METHOD(Redis, rawcommand);
#ifdef ZTS
#include "TSRM.h"
diff --git a/redis.c b/redis.c
index 6a536e0b..660798e0 100644
--- a/redis.c
+++ b/redis.c
@@ -266,7 +266,8 @@ static zend_function_entry redis_functions[] = {
PHP_ME(Redis, _unserialize, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Redis, client, NULL, ZEND_ACC_PUBLIC)
-
+ PHP_ME(Redis, command, NULL, ZEND_ACC_PUBLIC)
+
/* SCAN and friends */
PHP_ME(Redis, scan, arginfo_scan, ZEND_ACC_PUBLIC)
PHP_ME(Redis, hscan, arginfo_kscan, ZEND_ACC_PUBLIC)
@@ -3684,11 +3685,50 @@ PHP_METHOD(Redis, client) {
}
}
-/* proto array Redis::rawcommand()
- * proto array Redis::rawcommand('info', string cmd)
- * proto array Redis::rawcommand('getkeys', array cmd_args) */
+/* {{{ proto mixed Redis::rawcommand(string $command, [ $arg1 ... $argN]) */
PHP_METHOD(Redis, rawcommand) {
- REDIS_PROCESS_CMD(rawcommand, redis_read_variant_reply);
+ int argc = ZEND_NUM_ARGS(), cmd_len;
+ char *cmd = NULL;
+ RedisSock *redis_sock;
+ zval **z_args;
+
+ /* Sanity check on arguments */
+ z_args = emalloc(argc * sizeof(zval*));
+ if (argc < 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "Must pass at least one command keyword");
+ efree(z_args);
+ RETURN_FALSE;
+ } else if (zend_get_parameters_array(ht, argc, z_args) == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "Internal PHP error parsing arguments");
+ efree(z_args);
+ RETURN_FALSE;
+ } else if (redis_build_raw_cmd(z_args, argc, &cmd, &cmd_len TSRMLS_CC) < 0 ||
+ redis_sock_get(getThis(), &redis_sock TSRMLS_CC, 0) < 0)
+ {
+ if (cmd) efree(cmd);
+ efree(z_args);
+ RETURN_FALSE;
+ }
+
+ /* Clean up command array */
+ efree(z_args);
+
+ /* Execute our command */
+ REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len);
+ IF_ATOMIC() {
+ redis_read_variant_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU,redis_sock,NULL,NULL);
+ }
+ REDIS_PROCESS_RESPONSE(redis_read_variant_reply);
+}
+/* }}} */
+
+/* {{{ proto array Redis::command()
+ * proto array Redis::command('info', string cmd)
+ * proto array Redis::command('getkeys', array cmd_args) */
+PHP_METHOD(Redis, command) {
+ REDIS_PROCESS_CMD(command, redis_read_variant_reply);
}
/* }}} */
diff --git a/redis_cluster.c b/redis_cluster.c
index de9dcf07..3019b40e 100644
--- a/redis_cluster.c
+++ b/redis_cluster.c
@@ -209,6 +209,7 @@ zend_function_entry redis_cluster_functions[] = {
PHP_ME(RedisCluster, randomkey, NULL, ZEND_ACC_PUBLIC)
PHP_ME(RedisCluster, ping, NULL, ZEND_ACC_PUBLIC)
PHP_ME(RedisCluster, echo, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(RedisCluster, command, NULL, ZEND_ACC_PUBLIC)
PHP_ME(RedisCluster, rawcommand, NULL, ZEND_ACC_PUBLIC)
PHP_ME(RedisCluster, cluster, NULL, ZEND_ACC_PUBLIC)
PHP_ME(RedisCluster, client, NULL, ZEND_ACC_PUBLIC)
@@ -2199,27 +2200,8 @@ PHP_METHOD(RedisCluster, exec) {
CLUSTER_RESET_MULTI(c);
}
-/* {{{ proto bool RedisCluster::discard() */
-PHP_METHOD(RedisCluster, discard) {
- redisCluster *c = GET_CONTEXT();
-
- if(CLUSTER_IS_ATOMIC(c)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cluster is not in MULTI mode");
- RETURN_FALSE;
- }
-
- if(cluster_abort_exec(c TSRMLS_CC)<0) {
- CLUSTER_RESET_MULTI(c);
- }
-
- CLUSTER_FREE_QUEUE(c);
-
- RETURN_TRUE;
-}
-
/* Get a slot either by key (string) or host/port array */
-static short
-cluster_cmd_get_slot(redisCluster *c, zval *z_arg TSRMLS_DC)
+static short cluster_cmd_get_slot(redisCluster *c, zval *z_arg TSRMLS_DC)
{
int key_len, key_free;
zval **z_host, **z_port, *z_tmp = NULL;
@@ -2229,7 +2211,7 @@ cluster_cmd_get_slot(redisCluster *c, zval *z_arg TSRMLS_DC)
/* If it's a string, treat it as a key. Otherwise, look for a two
* element array */
if(Z_TYPE_P(z_arg)==IS_STRING || Z_TYPE_P(z_arg)==IS_LONG ||
- Z_TYPE_P(z_arg)==IS_DOUBLE)
+ Z_TYPE_P(z_arg)==IS_DOUBLE)
{
/* Allow for any scalar here */
if (Z_TYPE_P(z_arg) != IS_STRING) {
@@ -2253,7 +2235,7 @@ cluster_cmd_get_slot(redisCluster *c, zval *z_arg TSRMLS_DC)
zval_dtor(z_tmp);
efree(z_tmp);
}
- } else if (Z_TYPE_P(z_arg) == IS_ARRAY &&
+ } else if (Z_TYPE_P(z_arg) == IS_ARRAY &&
zend_hash_index_find(Z_ARRVAL_P(z_arg),0,(void**)&z_host)!=FAILURE &&
zend_hash_index_find(Z_ARRVAL_P(z_arg),1,(void**)&z_port)!=FAILURE &&
Z_TYPE_PP(z_host)==IS_STRING && Z_TYPE_PP(z_port)==IS_LONG)
@@ -2263,7 +2245,7 @@ cluster_cmd_get_slot(redisCluster *c, zval *z_arg TSRMLS_DC)
(unsigned short)Z_LVAL_PP(z_port));
/* Inform the caller if they've passed bad data */
- if(slot < 0) {
+ if(slot < 0) {
php_error_docref(0 TSRMLS_CC, E_WARNING, "Unknown node %s:%ld",
Z_STRVAL_PP(z_host), Z_LVAL_PP(z_port));
}
@@ -2276,6 +2258,24 @@ cluster_cmd_get_slot(redisCluster *c, zval *z_arg TSRMLS_DC)
return slot;
}
+/* {{{ proto bool RedisCluster::discard() */
+PHP_METHOD(RedisCluster, discard) {
+ redisCluster *c = GET_CONTEXT();
+
+ if(CLUSTER_IS_ATOMIC(c)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cluster is not in MULTI mode");
+ RETURN_FALSE;
+ }
+
+ if(cluster_abort_exec(c TSRMLS_CC)<0) {
+ CLUSTER_RESET_MULTI(c);
+ }
+
+ CLUSTER_FREE_QUEUE(c);
+
+ RETURN_TRUE;
+}
+
/* Generic handler for things we want directed at a given node, like SAVE,
* BGSAVE, FLUSHDB, FLUSHALL, etc */
static void
@@ -2856,7 +2856,7 @@ PHP_METHOD(RedisCluster, echo) {
rtype = CLUSTER_IS_ATOMIC(c) ? TYPE_BULK : TYPE_LINE;
if(cluster_send_slot(c,slot,cmd,cmd_len,rtype TSRMLS_CC)<0) {
zend_throw_exception(redis_cluster_exception_ce,
- "Unable to send commnad at the specificed node", 0 TSRMLS_CC);
+ "Unable to send command at the specificed node", 0 TSRMLS_CC);
efree(cmd);
RETURN_FALSE;
}
@@ -2873,11 +2873,66 @@ PHP_METHOD(RedisCluster, echo) {
}
/* }}} */
-/* {{{ proto array RedisCluster::rawcommand()
- * proto array RedisCluster::rawcommand('INFO', string cmd)
- * proto array RedisCluster::rawcommand('GETKEYS', array cmd_args) */
+/* {{{ proto mixed RedisCluster::rawcommand(string $key, string $cmd, [ $argv1 .. $argvN])
+ * proto mixed RedisCluster::rawcommand(array $host_port, string $cmd, [ $argv1 .. $argvN]) */
PHP_METHOD(RedisCluster, rawcommand) {
- CLUSTER_PROCESS_CMD(rawcommand, cluster_variant_resp, 0);
+ REDIS_REPLY_TYPE rtype;
+ int argc = ZEND_NUM_ARGS(), cmd_len;
+ redisCluster *c = GET_CONTEXT();
+ char *cmd = NULL;
+ zval **z_args;
+ short slot;
+
+ /* Sanity check on our arguments */
+ z_args = emalloc(argc * sizeof(zval*));
+ if (argc < 2) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "You must pass at least node information as well as at least a command.");
+ efree(z_args);
+ RETURN_FALSE;
+ } else if (zend_get_parameters_array(ht, argc, z_args) == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "Internal PHP error parsing method parameters.");
+ efree(z_args);
+ RETURN_FALSE;
+ } else if (redis_build_raw_cmd(z_args+1, argc-1, &cmd, &cmd_len TSRMLS_CC) ||
+ (slot = cluster_cmd_get_slot(c, z_args[0] TSRMLS_CC))<0)
+ {
+ if (cmd) efree(cmd);
+ efree(z_args);
+ RETURN_FALSE;
+ }
+
+ /* Free argument array */
+ efree(z_args);
+
+ /* Direct the command */
+ rtype = CLUSTER_IS_ATOMIC(c) ? TYPE_EOF : TYPE_LINE;
+ if (cluster_send_slot(c,slot,cmd,cmd_len,rtype TSRMLS_CC)<0) {
+ zend_throw_exception(redis_cluster_exception_ce,
+ "Unable to send command to the specified node", 0 TSRMLS_CC);
+ efree(cmd);
+ efree(z_args);
+ RETURN_FALSE;
+ }
+
+ /* Process variant response */
+ if (CLUSTER_IS_ATOMIC(c)) {
+ cluster_variant_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
+ } else {
+ void *ctx = NULL;
+ CLUSTER_ENQUEUE_RESPONSE(c, slot, cluster_variant_resp, ctx);
+ }
+
+ efree(cmd);
+}
+/* }}} */
+
+/* {{{ proto array RedisCluster::command()
+ * proto array RedisCluster::command('INFO', string cmd)
+ * proto array RedisCluster::command('GETKEYS', array cmd_args) */
+PHP_METHOD(RedisCluster, command) {
+ CLUSTER_PROCESS_CMD(command, cluster_variant_resp, 0);
}
/* }}} */
diff --git a/redis_cluster.h b/redis_cluster.h
index a5a0758a..3659d00e 100644
--- a/redis_cluster.h
+++ b/redis_cluster.h
@@ -237,6 +237,7 @@ PHP_METHOD(RedisCluster, config);
PHP_METHOD(RedisCluster, pubsub);
PHP_METHOD(RedisCluster, script);
PHP_METHOD(RedisCluster, slowlog);
+PHP_METHOD(RedisCluster, command);
/* SCAN and friends */
PHP_METHOD(RedisCluster, scan);
diff --git a/redis_commands.c b/redis_commands.c
index 03da0115..8d951dda 100644
--- a/redis_commands.c
+++ b/redis_commands.c
@@ -34,6 +34,51 @@ int redis_empty_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
return SUCCESS;
}
+/* Helper to construct a raw command. Given that the cluster and non cluster
+ * versions are different (RedisCluster needs an additional argument to direct
+ * the command) we take the start of our array and count */
+int redis_build_raw_cmd(zval **z_args, int argc, char **cmd, int *cmd_len TSRMLS_DC)
+{
+ smart_str cmdstr = {0};
+ int i;
+
+ /* Make sure our first argument is a string */
+ if (Z_TYPE_P(z_args[0]) != IS_STRING) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "When sending a 'raw' command, the first argument must be a string!");
+ return FAILURE;
+ }
+
+ /* Initialize our command string */
+ redis_cmd_init_sstr(&cmdstr, argc-1, Z_STRVAL_P(z_args[0]), Z_STRLEN_P(z_args[0]));
+
+ for (i = 1; i < argc; i++) {
+ switch (Z_TYPE_P(z_args[i])) {
+ case IS_STRING:
+ redis_cmd_append_sstr(&cmdstr, Z_STRVAL_P(z_args[i]),
+ Z_STRLEN_P(z_args[i]));
+ break;
+ case IS_LONG:
+ redis_cmd_append_sstr_long(&cmdstr,Z_LVAL_P(z_args[i]));
+ break;
+ case IS_DOUBLE:
+ redis_cmd_append_sstr_dbl(&cmdstr,Z_DVAL_P(z_args[i]));
+ break;
+ default:
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "Raw command arguments must be scalar values!");
+ efree(cmdstr.c);
+ return FAILURE;
+ }
+ }
+
+ /* Push command and length to caller */
+ *cmd = cmdstr.c;
+ *cmd_len = cmdstr.len;
+
+ return SUCCESS;
+}
+
/* Generic command where we just take a string and do nothing to it*/
int redis_str_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, char *kw,
char **cmd, int *cmd_len, short *slot, void **ctx)
@@ -2699,8 +2744,8 @@ int redis_sdiffstore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
}
/* COMMAND */
-int redis_rawcommand_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
- char **cmd, int *cmd_len, short *slot, void **ctx)
+int redis_command_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
+ char **cmd, int *cmd_len, short *slot, void **ctx)
{
char *kw=NULL;
zval *z_arg;
diff --git a/redis_commands.h b/redis_commands.h
index 1e456b59..053fd65a 100644
--- a/redis_commands.h
+++ b/redis_commands.h
@@ -21,6 +21,9 @@ typedef struct subscribeContext {
zend_fcall_info_cache cb_cache;
} subscribeContext;
+/* Construct a raw command */
+int redis_build_raw_cmd(zval **z_args, int argc, char **cmd, int *cmd_len TSRMLS_DC);
+
/* Redis command generics. Many commands share common prototypes meaning that
* we can write one function to handle all of them. For example, there are
* many COMMAND key value commands, or COMMAND key commands. */
@@ -212,9 +215,12 @@ int redis_sdiff_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
int redis_sdiffstore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
-int redis_rawcommand_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
+int redis_command_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
+int redis_rawcommand_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
+ char **cmd, int *cmd_len, short *slot, void **ctx);
+
int redis_fmt_scan_cmd(char **cmd, REDIS_SCAN_TYPE type, char *key, int key_len,
long it, char *pat, int pat_len, long count);