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:
authormichael-grunder <michael.grunder@gmail.com>2021-04-19 01:27:59 +0300
committermichael-grunder <michael.grunder@gmail.com>2021-06-22 20:16:23 +0300
commit4cb4cd0ee26fdd1a07f468b976f990dbb9de7ed0 (patch)
tree16046fc52ef712839ae0a252d20e9a9dacb69c21
parent2d72c55d7d0402bfdf147ba71cead38d2573e203 (diff)
Separate compression and create utility methods
This commit splits compression and serialization into two distinct parts and adds some utility functions so the user can compress/uncompress or pack/unpack data explicily. See #1939
-rw-r--r--library.c137
-rw-r--r--library.h5
-rw-r--r--php_redis.h6
-rw-r--r--redis.c49
-rw-r--r--redis_cluster.c25
-rw-r--r--redis_cluster.h12
-rw-r--r--redis_commands.c63
-rw-r--r--redis_commands.h31
-rw-r--r--tests/RedisTest.php65
-rw-r--r--tests/TestSuite.php12
10 files changed, 330 insertions, 75 deletions
diff --git a/library.c b/library.c
index 87b6bfa8..d15dad1e 100644
--- a/library.c
+++ b/library.c
@@ -2820,19 +2820,7 @@ static uint8_t crc8(unsigned char *input, size_t len) {
#endif
PHP_REDIS_API int
-redis_pack(RedisSock *redis_sock, zval *z, char **val, size_t *val_len)
-{
- char *buf;
- int valfree;
- size_t len;
-
- valfree = redis_serialize(redis_sock, z, &buf, &len);
- if (redis_sock->compression == REDIS_COMPRESSION_NONE) {
- *val = buf;
- *val_len = len;
- return valfree;
- }
-
+redis_compress(RedisSock *redis_sock, char **dst, size_t *dstlen, char *buf, size_t len) {
switch (redis_sock->compression) {
case REDIS_COMPRESSION_LZF:
#ifdef HAVE_REDIS_LZF
@@ -2845,9 +2833,8 @@ redis_pack(RedisSock *redis_sock, zval *z, char **val, size_t *val_len)
size = len + MIN(UINT_MAX - len, MAX(LZF_MARGIN, len / 25));
data = emalloc(size);
if ((res = lzf_compress(buf, len, data, size)) > 0) {
- if (valfree) efree(buf);
- *val = data;
- *val_len = res;
+ *dst = data;
+ *dstlen = res;
return 1;
}
efree(data);
@@ -2877,10 +2864,8 @@ redis_pack(RedisSock *redis_sock, zval *z, char **val, size_t *val_len)
data = emalloc(size);
size = ZSTD_compress(data, size, buf, len, level);
if (!ZSTD_isError(size)) {
- if (valfree) efree(buf);
- data = erealloc(data, size);
- *val = data;
- *val_len = size;
+ *dst = erealloc(data, size);
+ *dstlen = size;
return 1;
}
efree(data);
@@ -2928,22 +2913,21 @@ redis_pack(RedisSock *redis_sock, zval *z, char **val, size_t *val_len)
break;
}
- if (valfree) efree(buf);
- *val = lz4buf;
- *val_len = lz4len + REDIS_LZ4_HDR_SIZE;
+ *dst = lz4buf;
+ *dstlen = lz4len + REDIS_LZ4_HDR_SIZE;
return 1;
}
#endif
break;
}
- *val = buf;
- *val_len = len;
- return valfree;
+
+ *dst = buf;
+ *dstlen = len;
+ return 0;
}
PHP_REDIS_API int
-redis_unpack(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret)
-{
+redis_uncompress(RedisSock *redis_sock, char **dst, size_t *dstlen, const char *src, size_t len) {
switch (redis_sock->compression) {
case REDIS_COMPRESSION_LZF:
#ifdef HAVE_REDIS_LZF
@@ -2952,24 +2936,27 @@ redis_unpack(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret)
int i;
uint32_t res;
- if (val_len == 0)
+ if (len == 0)
break;
/* start from two-times bigger buffer and
* increase it exponentially if needed */
errno = E2BIG;
for (i = 2; errno == E2BIG; i *= 2) {
- data = emalloc(i * val_len);
- if ((res = lzf_decompress(val, val_len, data, i * val_len)) == 0) {
+ data = emalloc(i * len);
+ if ((res = lzf_decompress(src, len, data, i * len)) == 0) {
/* errno != E2BIG will brake for loop */
efree(data);
continue;
- } else if (redis_unserialize(redis_sock, data, res, z_ret) == 0) {
- ZVAL_STRINGL(z_ret, data, res);
}
- efree(data);
+
+ *dst = data;
+ *dstlen = res;
return 1;
}
+
+ efree(data);
+ break;
}
#endif
break;
@@ -2977,25 +2964,21 @@ redis_unpack(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret)
#ifdef HAVE_REDIS_ZSTD
{
char *data;
- unsigned long long len;
+ unsigned long long zlen;
- len = ZSTD_getFrameContentSize(val, val_len);
-
- if (len != ZSTD_CONTENTSIZE_ERROR && len != ZSTD_CONTENTSIZE_UNKNOWN && len <= INT_MAX)
- {
- size_t zlen;
+ zlen = ZSTD_getFrameContentSize(src, len);
+ if (zlen == ZSTD_CONTENTSIZE_ERROR || zlen == ZSTD_CONTENTSIZE_UNKNOWN || zlen > INT_MAX)
+ break;
- data = emalloc(len);
- zlen = ZSTD_decompress(data, len, val, val_len);
- if (ZSTD_isError(zlen) || zlen != len) {
- efree(data);
- break;
- } else if (redis_unserialize(redis_sock, data, zlen, z_ret) == 0) {
- ZVAL_STRINGL(z_ret, data, zlen);
- }
+ data = emalloc(zlen);
+ *dstlen = ZSTD_decompress(data, zlen, src, len);
+ if (ZSTD_isError(*dstlen) || *dstlen != zlen) {
efree(data);
- return 1;
+ break;
}
+
+ *dst = data;
+ return 1;
}
#endif
break;
@@ -3008,12 +2991,12 @@ redis_unpack(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret)
/* We must have at least enough bytes for our header, and can't have more than
* INT_MAX + our header size. */
- if (val_len < REDIS_LZ4_HDR_SIZE || val_len > INT_MAX + REDIS_LZ4_HDR_SIZE)
+ if (len < REDIS_LZ4_HDR_SIZE || len > INT_MAX + REDIS_LZ4_HDR_SIZE)
break;
/* Operate on copies in case our CRC fails */
- const char *copy = val;
- size_t copylen = val_len;
+ const char *copy = src;
+ size_t copylen = len;
/* Read in our header bytes */
memcpy(&lz4crc, copy, sizeof(uint8_t));
@@ -3028,23 +3011,59 @@ redis_unpack(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret)
/* Finally attempt decompression */
data = emalloc(datalen);
if (LZ4_decompress_safe(copy, data, copylen, datalen) > 0) {
- if (redis_unserialize(redis_sock, data, datalen, z_ret) == 0) {
- ZVAL_STRINGL(z_ret, data, datalen);
- }
- efree(data);
+ *dst = data;
+ *dstlen = datalen;
return 1;
}
+
efree(data);
}
#endif
break;
}
- return redis_unserialize(redis_sock, val, val_len, z_ret);
+
+ *dst = (char*)src;
+ *dstlen = len;
+ return 0;
+}
+
+PHP_REDIS_API int
+redis_pack(RedisSock *redis_sock, zval *z, char **val, size_t *val_len) {
+ size_t tmplen;
+ int tmpfree;
+ char *tmp;
+
+ /* First serialize */
+ tmpfree = redis_serialize(redis_sock, z, &tmp, &tmplen);
+
+ /* Now attempt compression */
+ if (redis_compress(redis_sock, val, val_len, tmp, tmplen)) {
+ if (tmpfree) efree(tmp);
+ return 1;
+ }
+
+ return tmpfree;
+}
+
+PHP_REDIS_API int
+redis_unpack(RedisSock *redis_sock, const char *src, int srclen, zval *zdst) {
+ size_t len;
+ char *buf;
+
+ /* Uncompress, then unserialize */
+ if (redis_uncompress(redis_sock, &buf, &len, src, srclen)) {
+ if (!redis_unserialize(redis_sock, buf, len, zdst)) {
+ ZVAL_STRINGL(zdst, buf, len);
+ }
+ efree(buf);
+ return 1;
+ }
+
+ return redis_unserialize(redis_sock, buf, len, zdst);
}
PHP_REDIS_API int
-redis_serialize(RedisSock *redis_sock, zval *z, char **val, size_t *val_len
- )
+redis_serialize(RedisSock *redis_sock, zval *z, char **val, size_t *val_len)
{
php_serialize_data_t ht;
diff --git a/library.h b/library.h
index f78f38c5..2ae55992 100644
--- a/library.h
+++ b/library.h
@@ -121,6 +121,11 @@ redis_key_prefix(RedisSock *redis_sock, char **key, size_t *key_len);
PHP_REDIS_API int
redis_unserialize(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret);
+PHP_REDIS_API int
+redis_compress(RedisSock *redis_sock, char **dst, size_t *dstlen, char *buf, size_t len);
+PHP_REDIS_API int
+redis_uncompress(RedisSock *redis_sock, char **dst, size_t *dstlen, const char *src, size_t len);
+
PHP_REDIS_API int redis_pack(RedisSock *redis_sock, zval *z, char **val, size_t *val_len);
PHP_REDIS_API int redis_unpack(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret);
diff --git a/php_redis.h b/php_redis.h
index 6b7b3be4..a0c5de40 100644
--- a/php_redis.h
+++ b/php_redis.h
@@ -165,9 +165,15 @@ PHP_METHOD(Redis, role);
PHP_METHOD(Redis, getLastError);
PHP_METHOD(Redis, clearLastError);
PHP_METHOD(Redis, _prefix);
+PHP_METHOD(Redis, _pack);
+PHP_METHOD(Redis, _unpack);
+
PHP_METHOD(Redis, _serialize);
PHP_METHOD(Redis, _unserialize);
+PHP_METHOD(Redis, _compress);
+PHP_METHOD(Redis, _uncompress);
+
PHP_METHOD(Redis, mset);
PHP_METHOD(Redis, msetnx);
PHP_METHOD(Redis, rpoplpush);
diff --git a/redis.c b/redis.c
index 230859db..bbf5bd89 100644
--- a/redis.c
+++ b/redis.c
@@ -286,6 +286,10 @@ static zend_function_entry redis_functions[] = {
PHP_ME(Redis, _prefix, arginfo_key, ZEND_ACC_PUBLIC)
PHP_ME(Redis, _serialize, arginfo_value, ZEND_ACC_PUBLIC)
PHP_ME(Redis, _unserialize, arginfo_value, ZEND_ACC_PUBLIC)
+ PHP_ME(Redis, _pack, arginfo_value, ZEND_ACC_PUBLIC)
+ PHP_ME(Redis, _unpack, arginfo_value, ZEND_ACC_PUBLIC)
+ PHP_ME(Redis, _compress, arginfo_value, ZEND_ACC_PUBLIC)
+ PHP_ME(Redis, _uncompress, arginfo_value, ZEND_ACC_PUBLIC)
PHP_ME(Redis, acl, arginfo_acl, ZEND_ACC_PUBLIC)
PHP_ME(Redis, append, arginfo_key_value, ZEND_ACC_PUBLIC)
PHP_ME(Redis, auth, arginfo_auth, ZEND_ACC_PUBLIC)
@@ -3294,6 +3298,51 @@ PHP_METHOD(Redis, _unserialize) {
redis_exception_ce);
}
+PHP_METHOD(Redis, _compress) {
+ RedisSock *redis_sock;
+
+ // Grab socket
+ if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
+ RETURN_FALSE;
+ }
+
+ redis_compress_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock);
+}
+
+PHP_METHOD(Redis, _uncompress) {
+ RedisSock *redis_sock;
+
+ // Grab socket
+ if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
+ RETURN_FALSE;
+ }
+
+ redis_uncompress_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock,
+ redis_exception_ce);
+}
+
+PHP_METHOD(Redis, _pack) {
+ RedisSock *redis_sock;
+
+ // Grab socket
+ if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
+ RETURN_FALSE;
+ }
+
+ redis_pack_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock);
+}
+
+PHP_METHOD(Redis, _unpack) {
+ RedisSock *redis_sock;
+
+ // Grab socket
+ if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
+ RETURN_FALSE;
+ }
+
+ redis_unpack_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock);
+}
+
/* {{{ proto Redis::getLastError() */
PHP_METHOD(Redis, getLastError) {
zval *object;
diff --git a/redis_cluster.c b/redis_cluster.c
index 402c23b7..8c451994 100644
--- a/redis_cluster.c
+++ b/redis_cluster.c
@@ -110,6 +110,10 @@ zend_function_entry redis_cluster_functions[] = {
PHP_ME(RedisCluster, _redir, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(RedisCluster, _serialize, arginfo_value, ZEND_ACC_PUBLIC)
PHP_ME(RedisCluster, _unserialize, arginfo_value, ZEND_ACC_PUBLIC)
+ PHP_ME(RedisCluster, _compress, arginfo_value, ZEND_ACC_PUBLIC)
+ PHP_ME(RedisCluster, _uncompress, arginfo_value, ZEND_ACC_PUBLIC)
+ PHP_ME(RedisCluster, _pack, arginfo_value, ZEND_ACC_PUBLIC)
+ PHP_ME(RedisCluster, _unpack, arginfo_value, ZEND_ACC_PUBLIC)
PHP_ME(RedisCluster, acl, arginfo_acl_cl, ZEND_ACC_PUBLIC)
PHP_ME(RedisCluster, append, arginfo_key_value, ZEND_ACC_PUBLIC)
PHP_ME(RedisCluster, bgrewriteaof, arginfo_key_or_address, ZEND_ACC_PUBLIC)
@@ -1970,6 +1974,27 @@ PHP_METHOD(RedisCluster, _unserialize) {
}
/* }}} */
+PHP_METHOD(RedisCluster, _compress) {
+ redisCluster *c = GET_CONTEXT();
+ redis_compress_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags);
+}
+
+PHP_METHOD(RedisCluster, _uncompress) {
+ redisCluster *c = GET_CONTEXT();
+ redis_uncompress_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags,
+ redis_cluster_exception_ce);
+}
+
+PHP_METHOD(RedisCluster, _pack) {
+ redisCluster *c = GET_CONTEXT();
+ redis_pack_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags);
+}
+
+PHP_METHOD(RedisCluster, _unpack) {
+ redisCluster *c = GET_CONTEXT();
+ redis_unpack_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags);
+}
+
/* {{{ proto array RedisCluster::_masters() */
PHP_METHOD(RedisCluster, _masters) {
redisCluster *c = GET_CONTEXT();
diff --git a/redis_cluster.h b/redis_cluster.h
index c6959fde..41f40c1a 100644
--- a/redis_cluster.h
+++ b/redis_cluster.h
@@ -13,7 +13,7 @@
redis_##name##_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags, &cmd, \
&cmd_len, &slot)
-/* Append information required to handle MULTI commands to the tail of our MULTI
+/* Append information required to handle MULTI commands to the tail of our MULTI
* linked list. */
#define CLUSTER_ENQUEUE_RESPONSE(c, slot, cb, ctx) \
clusterFoldItem *_item; \
@@ -69,8 +69,8 @@
CLUSTER_ENQUEUE_RESPONSE(c, slot, resp_func, ctx); \
RETURN_ZVAL(getThis(), 1, 0); \
} \
- resp_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, ctx);
-
+ resp_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, ctx);
+
/* More generic processing, where only the keyword differs */
#define CLUSTER_PROCESS_KW_CMD(kw, cmdfunc, resp_func, readcmd) \
redisCluster *c = GET_CONTEXT(); \
@@ -89,7 +89,7 @@
CLUSTER_ENQUEUE_RESPONSE(c, slot, resp_func, ctx); \
RETURN_ZVAL(getThis(), 1, 0); \
} \
- resp_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, ctx);
+ resp_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, ctx);
/* Create cluster context */
zend_object *create_cluster_context(zend_class_entry *class_type);
@@ -293,6 +293,10 @@ PHP_METHOD(RedisCluster, setoption);
PHP_METHOD(RedisCluster, _prefix);
PHP_METHOD(RedisCluster, _serialize);
PHP_METHOD(RedisCluster, _unserialize);
+PHP_METHOD(RedisCluster, _compress);
+PHP_METHOD(RedisCluster, _uncompress);
+PHP_METHOD(RedisCluster, _pack);
+PHP_METHOD(RedisCluster, _unpack);
PHP_METHOD(RedisCluster, _masters);
PHP_METHOD(RedisCluster, _redir);
diff --git a/redis_commands.c b/redis_commands.c
index 22d23b82..4d463ba1 100644
--- a/redis_commands.c
+++ b/redis_commands.c
@@ -4510,4 +4510,67 @@ void redis_unserialize_handler(INTERNAL_FUNCTION_PARAMETERS,
RETURN_ZVAL(&z_ret, 0, 0);
}
+void redis_compress_handler(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock) {
+ zend_string *zstr;
+ size_t len;
+ char *buf;
+ int cmp_free;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &zstr) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ cmp_free = redis_compress(redis_sock, &buf, &len, ZSTR_VAL(zstr), ZSTR_LEN(zstr));
+ RETVAL_STRINGL(buf, len);
+ if (cmp_free) efree(buf);
+}
+
+void redis_uncompress_handler(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
+ zend_class_entry *ex)
+{
+ zend_string *zstr;
+ size_t len;
+ char *buf;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &zstr) == FAILURE) {
+ RETURN_FALSE;
+ } else if (ZSTR_LEN(zstr) == 0 || redis_sock->compression == REDIS_COMPRESSION_NONE) {
+ RETURN_STR_COPY(zstr);
+ }
+
+ if (!redis_uncompress(redis_sock, &buf, &len, ZSTR_VAL(zstr), ZSTR_LEN(zstr))) {
+ zend_throw_exception(ex, "Invalid compressed data or uncompression error", 0);
+ RETURN_FALSE;
+ }
+
+ RETVAL_STRINGL(buf, len);
+ efree(buf);
+}
+
+void redis_pack_handler(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock) {
+ int valfree;
+ size_t len;
+ char *val;
+ zval *zv;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zv) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ valfree = redis_pack(redis_sock, zv, &val, &len);
+ RETVAL_STRINGL(val, len);
+ if (valfree) efree(val);
+}
+
+void redis_unpack_handler(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock) {
+ zend_string *str;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ if (redis_unpack(redis_sock, ZSTR_VAL(str), ZSTR_LEN(str), return_value) == 0) {
+ RETURN_STR_COPY(str);
+ }
+}
/* vim: set tabstop=4 softtabstop=4 expandtab shiftwidth=4: */
diff --git a/redis_commands.h b/redis_commands.h
index be30a310..6550d5c6 100644
--- a/redis_commands.h
+++ b/redis_commands.h
@@ -52,7 +52,7 @@ int redis_kv_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_key_str_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
- char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
+ char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_key_key_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
@@ -96,11 +96,11 @@ typedef int (*zrange_cb)(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *,char**,int*,int*,short*,void**);
int redis_zrange_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
- char *kw, char **cmd, int *cmd_len, int *withscores, short *slot,
+ char *kw, char **cmd, int *cmd_len, int *withscores, short *slot,
void **ctx);
int redis_zrangebyscore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
- char *kw, char **cmd, int *cmd_len, int *withscores, short *slot,
+ char *kw, char **cmd, int *cmd_len, int *withscores, short *slot,
void **ctx);
int redis_zdiff_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
@@ -143,7 +143,7 @@ int redis_georadiusbymember_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_s
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
/* Commands which need a unique construction mechanism. This is either because
- * they don't share a signature with any other command, or because there is
+ * they don't share a signature with any other command, or because there is
* specific processing we do (e.g. verifying subarguments) that make them
* unique */
@@ -174,7 +174,7 @@ int redis_hmset_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
int redis_hstrlen_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
-int redis_bitop_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
+int redis_bitop_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_bitcount_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
@@ -313,22 +313,29 @@ int redis_sentinel_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
int redis_sentinel_str_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
-/* Commands that don't communicate with Redis at all (such as getOption,
+/* Commands that don't communicate with Redis at all (such as getOption,
* setOption, _prefix, _serialize, etc). These can be handled in one place
- * with the method of grabbing our RedisSock* object in different ways
+ * with the method of grabbing our RedisSock* object in different ways
* depending if this is a Redis object or a RedisCluster object. */
-void redis_getoption_handler(INTERNAL_FUNCTION_PARAMETERS,
+void redis_getoption_handler(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, redisCluster *c);
-void redis_setoption_handler(INTERNAL_FUNCTION_PARAMETERS,
+void redis_setoption_handler(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, redisCluster *c);
-void redis_prefix_handler(INTERNAL_FUNCTION_PARAMETERS,
+void redis_prefix_handler(INTERNAL_FUNCTION_PARAMETERS,
+ RedisSock *redis_sock);
+void redis_serialize_handler(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock);
-void redis_serialize_handler(INTERNAL_FUNCTION_PARAMETERS,
+void redis_unserialize_handler(INTERNAL_FUNCTION_PARAMETERS,
+ RedisSock *redis_sock, zend_class_entry *ex);
+void redis_compress_handler(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock);
-void redis_unserialize_handler(INTERNAL_FUNCTION_PARAMETERS,
+void redis_uncompress_handler(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, zend_class_entry *ex);
+void redis_pack_handler(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock);
+void redis_unpack_handler(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock);
+
#endif
/* vim: set tabstop=4 softtabstop=4 expandtab shiftwidth=4: */
diff --git a/tests/RedisTest.php b/tests/RedisTest.php
index b6b6934c..d2d8ce9d 100644
--- a/tests/RedisTest.php
+++ b/tests/RedisTest.php
@@ -5089,6 +5089,71 @@ class Redis_Test extends TestSuite
}
}
+ public function testCompressHelpers() {
+ $compressors = self::getAvailableCompression();
+
+ $vals = ['foo', 12345, random_bytes(128), ''];
+
+ $oldcmp = $this->redis->getOption(Redis::OPT_COMPRESSION);
+
+ foreach ($compressors as $cmp) {
+ foreach ($vals as $val) {
+ $this->redis->setOption(Redis::OPT_COMPRESSION, $cmp);
+ $this->redis->set('cmpkey', $val);
+
+ /* Get the value raw */
+ $this->redis->setOption(Redis::OPT_COMPRESSION, Redis::COMPRESSION_NONE);
+ $raw = $this->redis->get('cmpkey');
+ $this->redis->setOption(Redis::OPT_COMPRESSION, $cmp);
+
+ $this->assertEquals($raw, $this->redis->_compress($val));
+
+ $uncompressed = $this->redis->get('cmpkey');
+ $this->assertEquals($uncompressed, $this->redis->_uncompress($raw));
+ }
+ }
+
+ $this->redis->setOption(Redis::OPT_COMPRESSION, $oldcmp);
+ }
+
+ public function testPackHelpers() {
+ list ($oldser, $oldcmp) = [
+ $this->redis->getOption(Redis::OPT_SERIALIZER),
+ $this->redis->getOption(Redis::OPT_COMPRESSION)
+ ];
+
+ foreach ($this->serializers as $ser) {
+ $compressors = self::getAvailableCompression();
+ foreach ($compressors as $cmp) {
+ $this->redis->setOption(Redis::OPT_SERIALIZER, $ser);
+ $this->redis->setOption(Redis::OPT_COMPRESSION, $cmp);
+
+ foreach (['foo', 12345, random_bytes(128), '', ['an', 'array']] as $v) {
+ /* Can only attempt the array if we're serializing */
+ if (is_array($v) && $ser == Redis::SERIALIZER_NONE)
+ continue;
+
+ $this->redis->set('packkey', $v);
+
+ /* Get the value raw */
+ $this->redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_NONE);
+ $this->redis->setOption(Redis::OPT_COMPRESSION, Redis::COMPRESSION_NONE);
+ $raw = $this->redis->get('packkey');
+ $this->redis->setOption(Redis::OPT_SERIALIZER, $ser);
+ $this->redis->setOption(Redis::OPT_COMPRESSION, $cmp);
+
+ $this->assertEquals($raw, $this->redis->_pack($v));
+
+ $unpacked = $this->redis->get('packkey');
+ $this->assertEquals($unpacked, $this->redis->_unpack($raw));
+ }
+ }
+ }
+
+ $this->redis->setOption(Redis::OPT_SERIALIZER, $oldser);
+ $this->redis->setOption(Redis::OPT_COMPRESSION, $oldcmp);
+ }
+
public function testPrefix() {
// no prefix
$this->redis->setOption(Redis::OPT_PREFIX, '');
diff --git a/tests/TestSuite.php b/tests/TestSuite.php
index c879b330..d4f737f9 100644
--- a/tests/TestSuite.php
+++ b/tests/TestSuite.php
@@ -39,6 +39,18 @@ class TestSuite
public function getPort() { return $this->i_port; }
public function getAuth() { return $this->auth; }
+ public static function getAvailableCompression() {
+ $result[] = Redis::COMPRESSION_NONE;
+ if (defined('Redis::COMPRESSION_LZF'))
+ $result[] = Redis::COMPRESSION_LZF;
+ if (defined('Redis::COMPRESSION_LZ4'))
+ $result[] = Redis::COMPRESSION_LZ4;
+ if (defined('Redis::COMPRESSION_ZSTD'))
+ $result[] = Redis::COMPRESSION_ZSTD;
+
+ return $result;
+ }
+
/**
* Returns the fully qualified host path,
* which may be used directly for php.ini parameters like session.save_path