@@ -32,8 +32,14 @@ PHPAPI int usleep(unsigned int useconds);
3232#define usleep Sleep
3333#endif
3434
35- #define UNSERIALIZE_ONLY_VALUES 0
36- #define UNSERIALIZE_ALL 1
35+ #define UNSERIALIZE_NONE 0
36+ #define UNSERIALIZE_KEYS 1
37+ #define UNSERIALIZE_VALS 2
38+ #define UNSERIALIZE_ALL 3
39+
40+ #define SCORE_DECODE_NONE 0
41+ #define SCORE_DECODE_INT 1
42+ #define SCORE_DECODE_DOUBLE 2
3743
3844extern zend_class_entry * redis_ce ;
3945extern zend_class_entry * redis_exception_ce ;
@@ -229,13 +235,13 @@ redis_sock_read_scan_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
229235 scan command this is. They all come back in slightly different ways */
230236 switch (type ) {
231237 case TYPE_SCAN :
232- return redis_sock_read_multibulk_reply_raw (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock , NULL , NULL );
238+ return redis_mbulk_reply_raw (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock , NULL , NULL );
233239 case TYPE_SSCAN :
234240 return redis_sock_read_multibulk_reply (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock , NULL , NULL );
235241 case TYPE_ZSCAN :
236- return redis_sock_read_multibulk_reply_zipped (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock , NULL , NULL );
242+ return redis_mbulk_reply_zipped_keys_dbl (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock , NULL , NULL );
237243 case TYPE_HSCAN :
238- return redis_sock_read_multibulk_reply_zipped_strings (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock , NULL , NULL );
244+ return redis_mbulk_reply_zipped_vals (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock , NULL , NULL );
239245 default :
240246 return -1 ;
241247 }
@@ -268,9 +274,10 @@ PHP_REDIS_API zval *redis_sock_read_multibulk_reply_zval(INTERNAL_FUNCTION_PARAM
268274 MAKE_STD_ZVAL (z_tab );
269275 array_init (z_tab );
270276
271- redis_sock_read_multibulk_reply_loop (INTERNAL_FUNCTION_PARAM_PASSTHRU ,
272- redis_sock , z_tab , numElems , 1 , UNSERIALIZE_ALL );
273- return z_tab ;
277+ redis_mbulk_reply_loop (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock , z_tab ,
278+ numElems , UNSERIALIZE_ALL );
279+
280+ return z_tab ;
274281}
275282
276283/**
@@ -1023,15 +1030,79 @@ PHP_REDIS_API void redis_long_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *
10231030 }
10241031}
10251032
1033+ /* Helper method to convert [key, value, key, value] into [key => value,
1034+ * key => value] when returning data to the caller. Depending on our decode
1035+ * flag we'll convert the value data types */
1036+ static void array_zip_values_and_scores (RedisSock * redis_sock , zval * z_tab ,
1037+ int decode TSRMLS_DC )
1038+ {
1039+
1040+ zval * z_ret ;
1041+ HashTable * keytable ;
1042+
1043+ MAKE_STD_ZVAL (z_ret );
1044+ array_init (z_ret );
1045+ keytable = Z_ARRVAL_P (z_tab );
1046+
1047+ for (zend_hash_internal_pointer_reset (keytable );
1048+ zend_hash_has_more_elements (keytable ) == SUCCESS ;
1049+ zend_hash_move_forward (keytable )) {
1050+
1051+ char * tablekey , * hkey , * hval ;
1052+ unsigned int tablekey_len ;
1053+ int hkey_len ;
1054+ unsigned long idx ;
1055+ zval * * z_key_pp , * * z_value_pp ;
10261056
1057+ zend_hash_get_current_key_ex (keytable , & tablekey , & tablekey_len , & idx , 0 , NULL );
1058+ if (zend_hash_get_current_data (keytable , (void * * )& z_key_pp ) == FAILURE ) {
1059+ continue ; /* this should never happen, according to the PHP people. */
1060+ }
1061+
1062+ /* get current value, a key */
1063+ convert_to_string (* z_key_pp );
1064+ hkey = Z_STRVAL_PP (z_key_pp );
1065+ hkey_len = Z_STRLEN_PP (z_key_pp );
10271066
1028- PHP_REDIS_API int redis_sock_read_multibulk_reply_zipped_with_flag (INTERNAL_FUNCTION_PARAMETERS , RedisSock * redis_sock , zval * z_tab , int flag ) {
1067+ /* move forward */
1068+ zend_hash_move_forward (keytable );
1069+
1070+ /* fetch again */
1071+ zend_hash_get_current_key_ex (keytable , & tablekey , & tablekey_len , & idx , 0 , NULL );
1072+ if (zend_hash_get_current_data (keytable , (void * * )& z_value_pp ) == FAILURE ) {
1073+ continue ; /* this should never happen, according to the PHP people. */
1074+ }
10291075
1030- /*
1031- int ret = redis_sock_read_multibulk_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab TSRMLS_CC);
1032- array_zip_values_and_scores(return_value, 0);
1033- */
1076+ /* get current value, a hash value now. */
1077+ hval = Z_STRVAL_PP (z_value_pp );
10341078
1079+ /* Decode the score depending on flag */
1080+ if (decode == SCORE_DECODE_INT && Z_STRLEN_PP (z_value_pp ) > 0 ) {
1081+ add_assoc_long_ex (z_ret , hkey , 1 + hkey_len , atoi (hval + 1 ));
1082+ } else if (decode == SCORE_DECODE_DOUBLE ) {
1083+ add_assoc_double_ex (z_ret , hkey , 1 + hkey_len , atof (hval ));
1084+ } else {
1085+ zval * z = NULL ;
1086+ MAKE_STD_ZVAL (z );
1087+ * z = * * z_value_pp ;
1088+ zval_copy_ctor (z );
1089+ add_assoc_zval_ex (z_ret , hkey , 1 + hkey_len , z );
1090+ }
1091+ }
1092+
1093+ /* replace */
1094+ zval_dtor (z_tab );
1095+ * z_tab = * z_ret ;
1096+ zval_copy_ctor (z_tab );
1097+ zval_dtor (z_ret );
1098+
1099+ efree (z_ret );
1100+ }
1101+
1102+ static int
1103+ redis_mbulk_reply_zipped (INTERNAL_FUNCTION_PARAMETERS , RedisSock * redis_sock ,
1104+ zval * z_tab , int unserialize , int decode )
1105+ {
10351106 char inbuf [1024 ];
10361107 int numElems ;
10371108 zval * z_multi_result ;
@@ -1061,10 +1132,12 @@ PHP_REDIS_API int redis_sock_read_multibulk_reply_zipped_with_flag(INTERNAL_FUNC
10611132 MAKE_STD_ZVAL (z_multi_result );
10621133 array_init (z_multi_result ); /* pre-allocate array for multi's results. */
10631134
1064- redis_sock_read_multibulk_reply_loop (INTERNAL_FUNCTION_PARAM_PASSTHRU ,
1065- redis_sock , z_multi_result , numElems , 1 , flag ? UNSERIALIZE_ALL : UNSERIALIZE_ONLY_VALUES );
1135+ /* Grab our key, value, key, value array */
1136+ redis_mbulk_reply_loop (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock ,
1137+ z_multi_result , numElems , unserialize );
10661138
1067- array_zip_values_and_scores (redis_sock , z_multi_result , 0 TSRMLS_CC );
1139+ /* Zip keys and values */
1140+ array_zip_values_and_scores (redis_sock , z_multi_result , decode TSRMLS_CC );
10681141
10691142 IF_MULTI_OR_PIPELINE () {
10701143 add_next_index_zval (z_tab , z_multi_result );
@@ -1078,13 +1151,35 @@ PHP_REDIS_API int redis_sock_read_multibulk_reply_zipped_with_flag(INTERNAL_FUNC
10781151 return 0 ;
10791152}
10801153
1081- PHP_REDIS_API int redis_sock_read_multibulk_reply_zipped (INTERNAL_FUNCTION_PARAMETERS , RedisSock * redis_sock , zval * z_tab , void * ctx ) {
1154+ /* Zipped key => value reply but we don't touch anything (e.g. CONFIG GET) */
1155+ PHP_REDIS_API int redis_mbulk_reply_zipped_raw (INTERNAL_FUNCTION_PARAMETERS , RedisSock * redis_sock , zval * z_tab , void * ctx )
1156+ {
1157+ return redis_mbulk_reply_zipped (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock ,
1158+ z_tab , UNSERIALIZE_NONE , SCORE_DECODE_NONE );
1159+ }
10821160
1083- return redis_sock_read_multibulk_reply_zipped_with_flag (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock , z_tab , 1 );
1161+ /* Zipped key => value reply unserializing keys and decoding the score as an integer (PUBSUB) */
1162+ PHP_REDIS_API int redis_mbulk_reply_zipped_keys_int (INTERNAL_FUNCTION_PARAMETERS , RedisSock * redis_sock ,
1163+ zval * z_tab , void * ctx )
1164+ {
1165+ return redis_mbulk_reply_zipped (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock ,
1166+ z_tab , UNSERIALIZE_KEYS , SCORE_DECODE_INT );
10841167}
10851168
1086- PHP_REDIS_API int redis_sock_read_multibulk_reply_zipped_strings (INTERNAL_FUNCTION_PARAMETERS , RedisSock * redis_sock , zval * z_tab , void * ctx ) {
1087- return redis_sock_read_multibulk_reply_zipped_with_flag (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock , z_tab , 0 );
1169+ /* Zipped key => value reply unserializing keys and decoding the score as a double (ZSET commands) */
1170+ PHP_REDIS_API int redis_mbulk_reply_zipped_keys_dbl (INTERNAL_FUNCTION_PARAMETERS , RedisSock * redis_sock ,
1171+ zval * z_tab , void * ctx )
1172+ {
1173+ return redis_mbulk_reply_zipped (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock ,
1174+ z_tab , UNSERIALIZE_KEYS , SCORE_DECODE_DOUBLE );
1175+ }
1176+
1177+ /* Zipped key => value reply where only the values are unserialized (e.g. HMGET) */
1178+ PHP_REDIS_API int redis_mbulk_reply_zipped_vals (INTERNAL_FUNCTION_PARAMETERS , RedisSock * redis_sock ,
1179+ zval * z_tab , void * ctx )
1180+ {
1181+ return redis_mbulk_reply_zipped (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock ,
1182+ z_tab , UNSERIALIZE_VALS , SCORE_DECODE_NONE );
10881183}
10891184
10901185PHP_REDIS_API void redis_1_response (INTERNAL_FUNCTION_PARAMETERS , RedisSock * redis_sock , zval * z_tab , void * ctx ) {
@@ -1500,8 +1595,8 @@ PHP_REDIS_API int redis_sock_read_multibulk_reply(INTERNAL_FUNCTION_PARAMETERS,
15001595 MAKE_STD_ZVAL (z_multi_result );
15011596 array_init (z_multi_result ); /* pre-allocate array for multi's results. */
15021597
1503- redis_sock_read_multibulk_reply_loop (INTERNAL_FUNCTION_PARAM_PASSTHRU ,
1504- redis_sock , z_multi_result , numElems , 1 , UNSERIALIZE_ALL );
1598+ redis_mbulk_reply_loop (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock ,
1599+ z_multi_result , numElems , UNSERIALIZE_ALL );
15051600
15061601 IF_MULTI_OR_PIPELINE () {
15071602 add_next_index_zval (z_tab , z_multi_result );
@@ -1516,7 +1611,7 @@ PHP_REDIS_API int redis_sock_read_multibulk_reply(INTERNAL_FUNCTION_PARAMETERS,
15161611/**
15171612 * Like multibulk reply, but don't touch the values, they won't be compressed. (this is used by HKEYS).
15181613 */
1519- PHP_REDIS_API int redis_sock_read_multibulk_reply_raw (INTERNAL_FUNCTION_PARAMETERS , RedisSock * redis_sock , zval * z_tab , void * ctx )
1614+ PHP_REDIS_API int redis_mbulk_reply_raw (INTERNAL_FUNCTION_PARAMETERS , RedisSock * redis_sock , zval * z_tab , void * ctx )
15201615{
15211616 char inbuf [1024 ];
15221617 int numElems ;
@@ -1547,8 +1642,8 @@ PHP_REDIS_API int redis_sock_read_multibulk_reply_raw(INTERNAL_FUNCTION_PARAMETE
15471642 MAKE_STD_ZVAL (z_multi_result );
15481643 array_init (z_multi_result ); /* pre-allocate array for multi's results. */
15491644
1550- redis_sock_read_multibulk_reply_loop (INTERNAL_FUNCTION_PARAM_PASSTHRU ,
1551- redis_sock , z_multi_result , numElems , 0 , UNSERIALIZE_ALL );
1645+ redis_mbulk_reply_loop (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock ,
1646+ z_multi_result , numElems , UNSERIALIZE_NONE );
15521647
15531648 IF_MULTI_OR_PIPELINE () {
15541649 add_next_index_zval (z_tab , z_multi_result );
@@ -1560,6 +1655,42 @@ PHP_REDIS_API int redis_sock_read_multibulk_reply_raw(INTERNAL_FUNCTION_PARAMETE
15601655 return 0 ;
15611656}
15621657
1658+ PHP_REDIS_API void
1659+ redis_mbulk_reply_loop (INTERNAL_FUNCTION_PARAMETERS , RedisSock * redis_sock ,
1660+ zval * z_tab , int count , int unserialize )
1661+ {
1662+ char * line ;
1663+ int len ;
1664+
1665+ while (count > 0 ) {
1666+ line = redis_sock_read (redis_sock , & len TSRMLS_CC );
1667+ if (line != NULL ) {
1668+ zval * z = NULL ;
1669+ int unwrap ;
1670+
1671+ /* We will attempt unserialization, if we're unserializing everything,
1672+ * or if we're unserializing keys and we're on a key, or we're
1673+ * unserializing values and we're on a value! */
1674+ unwrap = unserialize == UNSERIALIZE_ALL ||
1675+ (unserialize == UNSERIALIZE_KEYS && count % 2 == 0 ) ||
1676+ (unserialize == UNSERIALIZE_VALS && count % 2 != 0 );
1677+
1678+ if (unwrap && redis_unserialize (redis_sock , line , len , & z TSRMLS_CC )) {
1679+ efree (line );
1680+ add_next_index_zval (z_tab , z );
1681+ } else {
1682+ add_next_index_stringl (z_tab , line , len , 0 );
1683+ }
1684+ } else {
1685+ add_next_index_bool (z_tab , 0 );
1686+ }
1687+
1688+ count -- ;
1689+ }
1690+ }
1691+
1692+
1693+ /*
15631694PHP_REDIS_API int
15641695redis_sock_read_multibulk_reply_loop(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
15651696 zval *z_tab, int numElems, int unwrap_key, int unserialize_even_only)
@@ -1588,24 +1719,24 @@ redis_sock_read_multibulk_reply_loop(INTERNAL_FUNCTION_PARAMETERS, RedisSock *re
15881719 }
15891720 return 0;
15901721}
1722+ */
15911723
1592- /**
1593- * redis_sock_read_multibulk_reply_assoc
1594- */
1595- PHP_REDIS_API int redis_sock_read_multibulk_reply_assoc (INTERNAL_FUNCTION_PARAMETERS , RedisSock * redis_sock , zval * z_tab , void * ctx )
1724+ /* Specialized multibulk processing for HMGET where we need to pair requested
1725+ * keys with their returned values */
1726+ PHP_REDIS_API int redis_mbulk_reply_assoc (INTERNAL_FUNCTION_PARAMETERS , RedisSock * redis_sock , zval * z_tab , void * ctx )
15961727{
15971728 char inbuf [1024 ], * response ;
15981729 int response_len ;
1599- int i , numElems ;
1600- zval * z_multi_result ;
1730+ int i , numElems ;
1731+ zval * z_multi_result ;
16011732
16021733 zval * * z_keys = ctx ;
16031734
16041735 if (-1 == redis_check_eof (redis_sock TSRMLS_CC )) {
16051736 return -1 ;
16061737 }
16071738 if (php_stream_gets (redis_sock -> stream , inbuf , 1024 ) == NULL ) {
1608- redis_stream_close (redis_sock TSRMLS_CC );
1739+ redis_stream_close (redis_sock TSRMLS_CC );
16091740 redis_sock -> stream = NULL ;
16101741 redis_sock -> status = REDIS_SOCK_STATUS_FAILED ;
16111742 redis_sock -> mode = ATOMIC ;
@@ -1629,30 +1760,30 @@ PHP_REDIS_API int redis_sock_read_multibulk_reply_assoc(INTERNAL_FUNCTION_PARAME
16291760 for (i = 0 ; i < numElems ; ++ i ) {
16301761 response = redis_sock_read (redis_sock , & response_len TSRMLS_CC );
16311762 if (response != NULL ) {
1632- zval * z = NULL ;
1633- if (redis_unserialize (redis_sock , response , response_len , & z TSRMLS_CC ) == 1 ) {
1634- efree (response );
1635- add_assoc_zval_ex (z_multi_result , Z_STRVAL_P (z_keys [i ]), 1 + Z_STRLEN_P (z_keys [i ]), z );
1636- } else {
1637- add_assoc_stringl_ex (z_multi_result , Z_STRVAL_P (z_keys [i ]), 1 + Z_STRLEN_P (z_keys [i ]), response , response_len , 0 );
1638- }
1639- } else {
1640- add_assoc_bool_ex (z_multi_result , Z_STRVAL_P (z_keys [i ]), 1 + Z_STRLEN_P (z_keys [i ]), 0 );
1641- }
1642- zval_dtor (z_keys [i ]);
1643- efree (z_keys [i ]);
1763+ zval * z = NULL ;
1764+ if (redis_unserialize (redis_sock , response , response_len , & z TSRMLS_CC ) == 1 ) {
1765+ efree (response );
1766+ add_assoc_zval_ex (z_multi_result , Z_STRVAL_P (z_keys [i ]), 1 + Z_STRLEN_P (z_keys [i ]), z );
1767+ } else {
1768+ add_assoc_stringl_ex (z_multi_result , Z_STRVAL_P (z_keys [i ]), 1 + Z_STRLEN_P (z_keys [i ]), response , response_len , 0 );
1769+ }
1770+ } else {
1771+ add_assoc_bool_ex (z_multi_result , Z_STRVAL_P (z_keys [i ]), 1 + Z_STRLEN_P (z_keys [i ]), 0 );
1772+ }
1773+ zval_dtor (z_keys [i ]);
1774+ efree (z_keys [i ]);
16441775 }
16451776 efree (z_keys );
16461777
16471778 IF_MULTI_OR_PIPELINE () {
16481779 add_next_index_zval (z_tab , z_multi_result );
16491780 } else {
1650- * return_value = * z_multi_result ;
1651- zval_copy_ctor (return_value );
1652- INIT_PZVAL (return_value );
1653- zval_dtor (z_multi_result );
1654- efree (z_multi_result );
1655- }
1781+ * return_value = * z_multi_result ;
1782+ zval_copy_ctor (return_value );
1783+ INIT_PZVAL (return_value );
1784+ zval_dtor (z_multi_result );
1785+ efree (z_multi_result );
1786+ }
16561787 return 0 ;
16571788}
16581789
0 commit comments