Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0fbf639

Browse files
Merge branch 'hotfix/hmget_invalid_args'
2 parents 59a2886 + b144743 commit 0fbf639

File tree

2 files changed

+65
-63
lines changed

2 files changed

+65
-63
lines changed

redis.c

Lines changed: 62 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -4918,93 +4918,92 @@ PHP_METHOD(Redis, hIncrBy)
49184918

49194919
}
49204920

4921-
4921+
/* {{{ array Redis::hMget(string hash, array keys) */
49224922
PHP_METHOD(Redis, hMget) {
49234923
zval *object;
49244924
RedisSock *redis_sock;
4925-
char *key = NULL, *cmd;
4926-
int key_len, cmd_len, key_free;
4927-
zval *z_array;
4928-
zval **z_keys;
4929-
int nb_fields, i;
4930-
char *old_cmd = NULL;
4931-
4932-
zval **data;
4933-
HashTable *arr_hash;
4934-
HashPosition pointer;
4925+
char *key = NULL;
4926+
zval *z_array, **z_keys, **data;
4927+
int field_count, i, valid, key_len, key_free;
4928+
HashTable *ht_array;
4929+
HashPosition ptr;
4930+
smart_str cmd = {0};
49354931

4936-
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Osa",
4937-
&object, redis_ce,
4938-
&key, &key_len, &z_array) == FAILURE) {
4932+
// Make sure we can grab our arguments properly
4933+
if(zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Osa",
4934+
&object, redis_ce, &key, &key_len, &z_array)
4935+
== FAILURE)
4936+
{
49394937
RETURN_FALSE;
49404938
}
49414939

4942-
if (redis_sock_get(object, &redis_sock TSRMLS_CC, 0) < 0) {
4940+
// We'll need our socket
4941+
if(redis_sock_get(object, &redis_sock TSRMLS_CC, 0) < 0) {
49434942
RETURN_FALSE;
49444943
}
4945-
nb_fields = zend_hash_num_elements(Z_ARRVAL_P(z_array));
49464944

4947-
if( nb_fields == 0) {
4945+
// Grab member count and abort if we don't have any
4946+
if((field_count = zend_hash_num_elements(Z_ARRVAL_P(z_array))) == 0) {
49484947
RETURN_FALSE;
49494948
}
49504949

4951-
z_keys = ecalloc(nb_fields, sizeof(zval *));
4950+
// Prefix our key if we need to
4951+
key_free = redis_key_prefix(redis_sock, &key, &key_len TSRMLS_CC);
49524952

4953-
key_free = redis_key_prefix(redis_sock, &key, &key_len TSRMLS_CC);
4953+
// Allocate enough memory for the number of keys being requested
4954+
z_keys = ecalloc(field_count, sizeof(zval *));
49544955

4955-
cmd_len = redis_cmd_format(&cmd,
4956-
"*%d" _NL
4957-
"$5" _NL
4958-
"HMGET" _NL
4956+
// Grab our HashTable
4957+
ht_array = Z_ARRVAL_P(z_array);
49594958

4960-
"$%d" _NL /* key */
4961-
"%s" _NL
4962-
, nb_fields + 2
4963-
, key_len, key, key_len);
4964-
if(key_free) efree(key);
4959+
// Iterate through our keys, grabbing members that are valid
4960+
for(valid=0, zend_hash_internal_pointer_reset_ex(ht_array, &ptr);
4961+
zend_hash_get_current_data_ex(ht_array, (void**)&data, &ptr)==SUCCESS;
4962+
zend_hash_move_forward_ex(ht_array, &ptr))
4963+
{
4964+
// Make sure the data is a long or string, and if it's a string that
4965+
// it isn't empty. There is no reason to send empty length members.
4966+
if((Z_TYPE_PP(data) == IS_STRING && Z_STRLEN_PP(data)>0) ||
4967+
Z_TYPE_PP(data) == IS_LONG)
4968+
{
4969+
// This is a key we can ask for, copy it and set it in our array
4970+
MAKE_STD_ZVAL(z_keys[valid]);
4971+
*z_keys[valid] = **data;
4972+
zval_copy_ctor(z_keys[valid]);
4973+
convert_to_string(z_keys[valid]);
4974+
4975+
// Increment the number of valid keys we've encountered
4976+
valid++;
4977+
}
4978+
}
49654979

4966-
arr_hash = Z_ARRVAL_P(z_array);
4980+
// If we don't have any valid keys, we can abort here
4981+
if(valid == 0) {
4982+
if(key_free) efree(key);
4983+
efree(z_keys);
4984+
RETURN_FALSE;
4985+
}
49674986

4968-
for (i = 0, zend_hash_internal_pointer_reset_ex(arr_hash, &pointer);
4969-
zend_hash_get_current_data_ex(arr_hash, (void**) &data,
4970-
&pointer) == SUCCESS;
4971-
zend_hash_move_forward_ex(arr_hash, &pointer)) {
4987+
// Build command header. One extra argument for the hash key itself
4988+
redis_cmd_init_sstr(&cmd, valid+1, "HMGET", sizeof("HMGET")-1);
49724989

4973-
if (Z_TYPE_PP(data) == IS_LONG || Z_TYPE_PP(data) == IS_STRING) {
4990+
// Add the hash key
4991+
redis_cmd_append_sstr(&cmd, key, key_len);
49744992

4975-
old_cmd = cmd;
4976-
if (Z_TYPE_PP(data) == IS_LONG) {
4977-
cmd_len = redis_cmd_format(&cmd, "%s" "$%d" _NL "%d" _NL
4978-
, cmd, cmd_len
4979-
, integer_length(Z_LVAL_PP(data)), (int)Z_LVAL_PP(data));
4980-
} else if (Z_TYPE_PP(data) == IS_STRING) {
4981-
cmd_len = redis_cmd_format(&cmd, "%s" "$%d" _NL "%s" _NL
4982-
, cmd, cmd_len
4983-
, Z_STRLEN_PP(data), Z_STRVAL_PP(data), Z_STRLEN_PP(data));
4984-
}
4985-
efree(old_cmd);
4986-
/* save context */
4987-
MAKE_STD_ZVAL(z_keys[i]);
4988-
*z_keys[i] = **data;
4989-
zval_copy_ctor(z_keys[i]);
4990-
convert_to_string(z_keys[i]);
4993+
// Free key memory if it was prefixed
4994+
if(key_free) efree(key);
49914995

4992-
i++;
4993-
}
4996+
// Iterate our keys, appending them as arguments
4997+
for(i=0;i<valid;i++) {
4998+
redis_cmd_append_sstr(&cmd, Z_STRVAL_P(z_keys[i]), Z_STRLEN_P(z_keys[i]));
49944999
}
49955000

4996-
// This is a failure if none of the keys were valid
4997-
if(i == 0) {
4998-
efree(cmd);
4999-
efree(z_keys);
5000-
RETURN_FALSE;
5001+
// Kick off our request
5002+
REDIS_PROCESS_REQUEST(redis_sock, cmd.c, cmd.len);
5003+
IF_ATOMIC() {
5004+
redis_sock_read_multibulk_reply_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL, z_keys);
50015005
}
5002-
5003-
REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len);
5004-
IF_ATOMIC() {
5005-
redis_sock_read_multibulk_reply_assoc(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL, z_keys);
5006-
}
5007-
REDIS_PROCESS_RESPONSE_CLOSURE(redis_sock_read_multibulk_reply_assoc, z_keys);
5006+
REDIS_PROCESS_RESPONSE_CLOSURE(redis_sock_read_multibulk_reply_assoc, z_keys);
50085007
}
50095008

50105009
PHP_METHOD(Redis, hMset)

tests/TestRedis.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2285,6 +2285,9 @@ public function testHashes() {
22852285
// Test with an array populated with things we can't use as keys
22862286
$this->assertTrue($this->redis->hmget('h', Array(false,NULL,false)) === FALSE);
22872287

2288+
// Test with some invalid keys mixed in (which should just be ignored)
2289+
$this->assertTrue(array('x'=>'123','y'=>'456','z'=>'abc') === $this->redis->hMget('h',Array('x',null,'y','','z',false)));
2290+
22882291
// hmget/hmset with numeric fields
22892292
$this->redis->del('h');
22902293
$this->assertTrue(TRUE === $this->redis->hMset('h', array(123 => 'x', 'y' => 456)));

0 commit comments

Comments
 (0)