From e0a4dc23f0dd51696eed7249ff048072bdc5cde0 Mon Sep 17 00:00:00 2001 From: gowithrain Date: Wed, 30 Jul 2014 10:41:48 +0800 Subject: [PATCH] add command func and update INFO command --- library.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++----- library.h | 1 + php_redis.h | 3 ++ redis.c | 85 +++++++++++++++++++++++++++++++++++ 4 files changed, 204 insertions(+), 10 deletions(-) diff --git a/library.c b/library.c index 40d43fa2bf..1e7966a30a 100644 --- a/library.c +++ b/library.c @@ -665,7 +665,9 @@ PHP_REDIS_API void redis_info_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock * char *key, *value, *p; int is_numeric; zval *z_multi_result; - + zval *z_item = NULL; + char *item_key = NULL; + if ((response = redis_sock_read(redis_sock, &response_len TSRMLS_CC)) == NULL) { RETURN_FALSE; } @@ -679,13 +681,29 @@ PHP_REDIS_API void redis_info_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock * cur = response; while(1) { - /* skip comments and empty lines */ - if(*cur == '#' || *cur == '\r') { - if(!(cur = strchr(cur, '\n'))) - break; - cur++; - continue; - } + /* skip empty lines */ + if(*cur == '\r') { + if(!(cur = strchr(cur, '\n'))) + break; + cur++; + continue; + } else if (*cur == '#') { + pos = strchr(cur, '\r'); + if (pos == NULL || pos+1 == NULL || *(pos+1) != '\n') + break; + item_key = emalloc(pos-cur+1); + memcpy(item_key, cur, pos-cur); + item_key[pos-cur] = '\0'; + MAKE_STD_ZVAL(z_item); + array_init(z_item); + add_assoc_zval(z_multi_result, item_key, z_item); + efree(item_key); + cur = pos+2; + continue; + } + if (z_item == NULL) { + break; + } /* key */ pos = strchr(cur, ':'); @@ -717,10 +735,10 @@ PHP_REDIS_API void redis_info_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock * } if(is_numeric == 1) { - add_assoc_long(z_multi_result, key, atol(value)); + add_assoc_long(z_item, key, atol(value)); efree(value); } else { - add_assoc_string(z_multi_result, key, value, 0); + add_assoc_string(z_item, key, value, 0); } efree(key); } @@ -1387,6 +1405,93 @@ PHP_REDIS_API int redis_sock_set_err(RedisSock *redis_sock, const char *msg, int return 0; } +PHP_REDIS_API int redis_sock_read_generic_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) { + char inbuf[1024]; + int numElems; + zval *z_multi_result; + + if(-1 == redis_check_eof(redis_sock TSRMLS_CC)) { + return -1; + } + if(php_stream_gets(redis_sock->stream, inbuf, 1024) == NULL) { + redis_stream_close(redis_sock TSRMLS_CC); + redis_sock->stream = NULL; + redis_sock->status = REDIS_SOCK_STATUS_FAILED; + redis_sock->mode = ATOMIC; + redis_sock->watching = 0; + zend_throw_exception(redis_exception_ce, "read error on connection", 0 TSRMLS_CC); + return -1; + } + + if (inbuf[0] == '*') { + numElems = atoi(inbuf+1); + MAKE_STD_ZVAL(z_multi_result); + array_init(z_multi_result); /* pre-allocate array for multi's results. */ + + redis_sock_read_multibulk_reply_loop(INTERNAL_FUNCTION_PARAM_PASSTHRU, + redis_sock, z_multi_result, numElems, 1, UNSERIALIZE_ALL); + + IF_MULTI_OR_PIPELINE() { + add_next_index_zval(z_tab, z_multi_result); + } else { + *return_value = *z_multi_result; + efree(z_multi_result); + } + } else if (inbuf[0] == '$') { + int size = atoi(inbuf+1); + if (size == -1) { + RETVAL_NULL(); + } else { + char *resp = redis_sock_read_bulk_reply(redis_sock, size TSRMLS_CC); + RETVAL_STRINGL(resp, size, 0); + } + } else if (inbuf[0] == ':') { + /// int + long long ret = atoll(inbuf + 1); + IF_MULTI_OR_PIPELINE() { + if(ret > LONG_MAX) { /* overflow */ + add_next_index_stringl(z_tab, inbuf+1, strlen(inbuf+1)-2, 1); + } else { + add_next_index_long(z_tab, (long)ret); + } + } else { + if(ret > LONG_MAX) { /* overflow */ + RETVAL_STRINGL(inbuf+1, strlen(inbuf+1)-2, 1); + } else { + RETVAL_LONG((long)ret); + } + } + } else if (inbuf[0] == '-') { + /// error + int err_len = strlen(inbuf+1) - 2; + redis_sock_set_err(redis_sock, inbuf+1, err_len); + IF_MULTI_OR_PIPELINE() { + add_next_index_bool(z_tab, 0); + return; + } else { + RETVAL_FALSE; + } + } else if (inbuf[0] == '+') { + int inbuf_len = strlen(inbuf)-2; + IF_MULTI_OR_PIPELINE() { + add_next_index_stringl(z_tab, inbuf, inbuf_len, 1); + } else { + RETVAL_STRINGL(inbuf, inbuf_len, 1); + } + } else { + IF_MULTI_OR_PIPELINE() { + add_next_index_bool(z_tab, 0); + } else { + RETVAL_FALSE; + } + return -1; + } + + //zval_copy_ctor(return_value); + return 0; +} + + /** * redis_sock_read_multibulk_reply */ diff --git a/library.h b/library.h index 652db6f407..07c981189e 100644 --- a/library.h +++ b/library.h @@ -30,6 +30,7 @@ PHP_REDIS_API int redis_sock_server_open(RedisSock *redis_sock, int force_connec PHP_REDIS_API int redis_sock_disconnect(RedisSock *redis_sock TSRMLS_DC); PHP_REDIS_API zval *redis_sock_read_multibulk_reply_zval(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock); PHP_REDIS_API char *redis_sock_read_bulk_reply(RedisSock *redis_sock, int bytes TSRMLS_DC); +PHP_REDIS_API int redis_sock_read_generic_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx); PHP_REDIS_API int redis_sock_read_multibulk_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *_z_tab, void *ctx); PHP_REDIS_API int redis_sock_read_multibulk_reply_raw(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx); PHP_REDIS_API int redis_sock_read_multibulk_reply_loop(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, int numElems, int unwrap_key, int unserialize_even_only); diff --git a/php_redis.h b/php_redis.h index e6ec1ef2f8..a87dd19315 100644 --- a/php_redis.h +++ b/php_redis.h @@ -206,6 +206,9 @@ PHP_METHOD(Redis, isConnected); PHP_METHOD(Redis, getPersistentID); PHP_METHOD(Redis, getAuth); +/// command +PHP_METHOD(Redis, command); + #ifdef PHP_WIN32 #define PHP_REDIS_API __declspec(dllexport) #else diff --git a/redis.c b/redis.c index 3591aba1c6..e3e0e84328 100644 --- a/redis.c +++ b/redis.c @@ -283,6 +283,8 @@ static zend_function_entry redis_functions[] = { PHP_ME(Redis, wait, NULL, ZEND_ACC_PUBLIC) PHP_ME(Redis, pubsub, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Redis, command, NULL, ZEND_ACC_PUBLIC) + /* aliases */ PHP_MALIAS(Redis, open, connect, NULL, ZEND_ACC_PUBLIC) PHP_MALIAS(Redis, popen, pconnect, NULL, ZEND_ACC_PUBLIC) @@ -7190,4 +7192,87 @@ PHP_METHOD(Redis, zscan) { generic_scan_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, TYPE_ZSCAN); } +PHP_METHOD(Redis, command) +{ + char *cmd; + int cmd_len; + + zval **z_args; + char **params; + int *params_len; + int argc = ZEND_NUM_ARGS(), i; + RedisSock *redis_sock = NULL; + smart_str buf = {0}; + int key_free = 0; + + /* get redis socket */ + if (redis_sock_get(getThis(), &redis_sock TSRMLS_CC, 0) < 0) { + RETURN_FALSE; + } + + /* fetch args */ + z_args = emalloc(argc * sizeof(zval*)); + if(zend_get_parameters_array(ht, argc, z_args) == FAILURE + || argc < 1 + || Z_TYPE_P(z_args[0]) != IS_STRING /* operation must be a string. */ + ) { + efree(z_args); + RETURN_FALSE; + } + + params = emalloc((argc) * sizeof(char*)); + params_len = emalloc((argc) * sizeof(int)); + + /* prefix params */ + for(i = 0; i < argc; ++i) { + convert_to_string(z_args[i]); + + params[i] = Z_STRVAL_P(z_args[i]); + params_len[i] = Z_STRLEN_P(z_args[i]); + // key_free = redis_key_prefix(redis_sock, ¶ms[i], ¶ms_len[i] TSRMLS_CC); + } + + /* start building the command */ + smart_str_appendc(&buf, '*'); + smart_str_append_long(&buf, argc); /* +1 for BITOP command */ + smart_str_appendl(&buf, _NL, sizeof(_NL) - 1); + + /* add params */ + for(i = 0; i < argc; ++i) { + smart_str_appendc(&buf, '$'); + smart_str_append_long(&buf, params_len[i]); + smart_str_appendl(&buf, _NL, sizeof(_NL) - 1); + smart_str_appendl(&buf, params[i], params_len[i]); + smart_str_appendl(&buf, _NL, sizeof(_NL) - 1); + } + /* end string */ + smart_str_0(&buf); + cmd = buf.c; + cmd_len = buf.len; + + /* cleanup */ + if(key_free) + for(i = 0; i < argc; ++i) { + efree(params[i]); + } + efree(params); + efree(params_len); + efree(z_args); + + /* send */ + 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); */ + IF_ATOMIC() { + if (redis_sock_read_generic_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU, + redis_sock, NULL, NULL) < 0) { + RETURN_FALSE; + } + } + REDIS_PROCESS_RESPONSE(redis_sock_read_generic_reply); + +} + /* vim: set tabstop=4 softtabstops=4 noexpandtab shiftwidth=4: */