@@ -2293,7 +2293,8 @@ int redis_set_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
22932293 char * * cmd , int * cmd_len , short * slot , void * * ctx )
22942294{
22952295 char * key = NULL , * exp_type = NULL , * set_type = NULL ;
2296- zval * z_value , * z_opts = NULL ;
2296+ zend_string * ifeq = NULL , * tmp = NULL ;
2297+ zval * z_value , * z_opts = NULL ;
22972298 smart_string cmdstr = {0 };
22982299 zend_long expire = -1 ;
22992300 zend_bool get = 0 ;
@@ -2312,7 +2313,6 @@ int redis_set_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
23122313 return FAILURE ;
23132314 }
23142315
2315-
23162316 // Check for an options array
23172317 if (z_opts && Z_TYPE_P (z_opts ) == IS_ARRAY ) {
23182318 HashTable * kt = Z_ARRVAL_P (z_opts );
@@ -2329,11 +2329,14 @@ int redis_set_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
23292329 zend_string_equals_literal_ci (zkey , "PXAT" ))
23302330 ) {
23312331 if (redis_try_get_expiry (v , & expire ) == FAILURE || expire < 1 ) {
2332+ zend_tmp_string_release (tmp );
23322333 setExpiryWarning (v );
23332334 return FAILURE ;
23342335 }
23352336
23362337 exp_type = ZSTR_VAL (zkey );
2338+ } else if (zkey && !ifeq && zend_string_equals_literal_ci (zkey , "IFEQ" )) {
2339+ ifeq = zval_get_tmp_string (v , & tmp );
23372340 } else if (Z_TYPE_P (v ) == IS_STRING ) {
23382341 if (zend_string_equals_literal_ci (Z_STR_P (v ), "KEEPTTL" )) {
23392342 keep_ttl = 1 ;
@@ -2348,6 +2351,7 @@ int redis_set_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
23482351 } ZEND_HASH_FOREACH_END ();
23492352 } else if (z_opts && Z_TYPE_P (z_opts ) != IS_NULL ) {
23502353 if (redis_try_get_expiry (z_opts , & expire ) == FAILURE || expire < 1 ) {
2354+ zend_tmp_string_release (tmp );
23512355 setExpiryWarning (z_opts );
23522356 return FAILURE ;
23532357 }
@@ -2356,18 +2360,28 @@ int redis_set_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
23562360 /* Protect the user from syntax errors but give them some info about what's wrong */
23572361 if (exp_type && keep_ttl ) {
23582362 php_error_docref (NULL , E_WARNING , "KEEPTTL can't be combined with EX or PX option" );
2363+ zend_tmp_string_release (tmp );
2364+ return FAILURE ;
2365+ }
2366+
2367+ /* You can't use IFEQ with NX or XX */
2368+ if (set_type && ifeq ) {
2369+ php_error_docref (NULL , E_WARNING , "IFEQ can't be combined with NX or XX option" );
2370+ zend_tmp_string_release (tmp );
23592371 return FAILURE ;
23602372 }
23612373
23622374 /* Backward compatibility: If we are passed no options except an EXPIRE ttl, we
23632375 * actually execute a SETEX command */
23642376 if (expire > 0 && !exp_type && !set_type && !keep_ttl ) {
23652377 * cmd_len = REDIS_CMD_SPPRINTF (cmd , "SETEX" , "klv" , key , key_len , expire , z_value );
2378+ zend_tmp_string_release (tmp );
23662379 return SUCCESS ;
23672380 }
23682381
23692382 /* Calculate argc based on options set */
2370- int argc = 2 + (exp_type ? 2 : 0 ) + (set_type != NULL ) + (keep_ttl != 0 ) + get ;
2383+ int argc = 2 + (ifeq ? 2 : 0 ) + (exp_type ? 2 : 0 ) + (set_type != NULL ) +
2384+ (keep_ttl != 0 ) + get ;
23712385
23722386 /* Initial SET <key> <value> */
23732387 redis_cmd_init_sstr (& cmdstr , argc , "SET" , 3 );
@@ -2379,15 +2393,22 @@ int redis_set_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
23792393 redis_cmd_append_sstr_long (& cmdstr , (long )expire );
23802394 }
23812395
2382- if (set_type )
2396+ if (ifeq ) {
2397+ REDIS_CMD_APPEND_SSTR_STATIC (& cmdstr , "IFEQ" );
2398+ redis_cmd_append_sstr_zstr (& cmdstr , ifeq );
2399+ } else if (set_type ) {
23832400 redis_cmd_append_sstr (& cmdstr , set_type , strlen (set_type ));
2401+ }
2402+
23842403 if (keep_ttl )
23852404 redis_cmd_append_sstr (& cmdstr , "KEEPTTL" , 7 );
23862405 if (get ) {
23872406 REDIS_CMD_APPEND_SSTR_STATIC (& cmdstr , "GET" );
23882407 * ctx = PHPREDIS_CTX_PTR ;
23892408 }
23902409
2410+ zend_tmp_string_release (tmp );
2411+
23912412 /* Push command and length to the caller */
23922413 * cmd = cmdstr .c ;
23932414 * cmd_len = cmdstr .len ;
0 commit comments