@@ -276,6 +276,7 @@ static zend_function_entry redis_functions[] = {
276
276
PHP_ME (Redis , isConnected , NULL , ZEND_ACC_PUBLIC )
277
277
278
278
PHP_ME (Redis , wait , NULL , ZEND_ACC_PUBLIC )
279
+ PHP_ME (Redis , pubsub , NULL , ZEND_ACC_PUBLIC )
279
280
280
281
/* aliases */
281
282
PHP_MALIAS (Redis , open , connect , NULL , ZEND_ACC_PUBLIC )
@@ -6077,6 +6078,169 @@ PHP_METHOD(Redis, wait) {
6077
6078
REDIS_PROCESS_RESPONSE (redis_long_response );
6078
6079
}
6079
6080
6081
+ /*
6082
+ * Construct a PUBSUB command
6083
+ */
6084
+ PHPAPI int
6085
+ redis_build_pubsub_cmd (RedisSock * redis_sock , char * * ret , PUBSUB_TYPE type ,
6086
+ zval * arg TSRMLS_CC )
6087
+ {
6088
+ HashTable * ht_chan ;
6089
+ HashPosition ptr ;
6090
+ zval * * z_ele ;
6091
+ char * key ;
6092
+ int cmd_len , key_len , key_free ;
6093
+ smart_str cmd = {0 };
6094
+
6095
+ if (type == PUBSUB_CHANNELS ) {
6096
+ if (arg ) {
6097
+ // Get string argument and length.
6098
+ key = Z_STRVAL_P (arg );
6099
+ key_len = Z_STRLEN_P (arg );
6100
+
6101
+ // Prefix if necissary
6102
+ key_free = redis_key_prefix (redis_sock , & key , & key_len TSRMLS_CC );
6103
+
6104
+ // With a pattern
6105
+ cmd_len = redis_cmd_format_static (ret , "PUBSUB" , "ss" , "CHANNELS" , sizeof ("CHANNELS" )- 1 ,
6106
+ key , key_len );
6107
+
6108
+ // Free the channel name if we prefixed it
6109
+ if (key_free ) efree (key );
6110
+
6111
+ // Return command length
6112
+ return cmd_len ;
6113
+ } else {
6114
+ // No pattern
6115
+ return redis_cmd_format_static (ret , "PUBSUB" , "s" , "CHANNELS" , sizeof ("CHANNELS" )- 1 );
6116
+ }
6117
+ } else if (type == PUBSUB_NUMSUB ) {
6118
+ ht_chan = Z_ARRVAL_P (arg );
6119
+
6120
+ // Add PUBSUB and NUMSUB bits
6121
+ redis_cmd_init_sstr (& cmd , zend_hash_num_elements (ht_chan )+ 1 , "PUBSUB" , sizeof ("PUBSUB" )- 1 );
6122
+ redis_cmd_append_sstr (& cmd , "NUMSUB" , sizeof ("NUMSUB" )- 1 );
6123
+
6124
+ // Iterate our elements
6125
+ for (zend_hash_internal_pointer_reset_ex (ht_chan , & ptr );
6126
+ zend_hash_get_current_data_ex (ht_chan , (void * * )& z_ele , & ptr )== SUCCESS ;
6127
+ zend_hash_move_forward_ex (ht_chan , & ptr ))
6128
+ {
6129
+ char * key ;
6130
+ int key_len , key_free ;
6131
+ zval * z_tmp = NULL ;
6132
+
6133
+ if (Z_TYPE_PP (z_ele ) == IS_STRING ) {
6134
+ key = Z_STRVAL_PP (z_ele );
6135
+ key_len = Z_STRLEN_PP (z_ele );
6136
+ } else {
6137
+ MAKE_STD_ZVAL (z_tmp );
6138
+ * z_tmp = * * z_ele ;
6139
+ zval_copy_ctor (z_tmp );
6140
+ convert_to_string (z_tmp );
6141
+
6142
+ key = Z_STRVAL_P (z_tmp );
6143
+ key_len = Z_STRLEN_P (z_tmp );
6144
+ }
6145
+
6146
+ // Apply prefix if required
6147
+ key_free = redis_key_prefix (redis_sock , & key , & key_len TSRMLS_CC );
6148
+
6149
+ // Append this channel
6150
+ redis_cmd_append_sstr (& cmd , key , key_len );
6151
+
6152
+ // Free key if prefixed
6153
+ if (key_free ) efree (key );
6154
+
6155
+ // Free our temp var if we converted from something other than a string
6156
+ if (z_tmp ) {
6157
+ zval_dtor (z_tmp );
6158
+ efree (z_tmp );
6159
+ z_tmp = NULL ;
6160
+ }
6161
+ }
6162
+
6163
+ // Set return
6164
+ * ret = cmd .c ;
6165
+ return cmd .len ;
6166
+ } else if (type == PUBSUB_NUMPAT ) {
6167
+ return redis_cmd_format_static (ret , "PUBSUB" , "s" , "NUMPAT" , sizeof ("NUMPAT" )- 1 );
6168
+ }
6169
+
6170
+ // Shouldn't ever happen
6171
+ return -1 ;
6172
+ }
6173
+
6174
+ /*
6175
+ * {{{ proto Redis::pubsub("channels", pattern);
6176
+ * proto Redis::pubsub("numsub", Array channels);
6177
+ * proto Redis::pubsub("numpat"); }}}
6178
+ */
6179
+ PHP_METHOD (Redis , pubsub ) {
6180
+ zval * object ;
6181
+ RedisSock * redis_sock ;
6182
+ char * keyword , * cmd ;
6183
+ int kw_len , cmd_len ;
6184
+ PUBSUB_TYPE type ;
6185
+ zval * arg = NULL ;
6186
+
6187
+ // Parse arguments
6188
+ if (zend_parse_method_parameters (ZEND_NUM_ARGS () TSRMLS_CC , getThis (), "Os|z" ,
6189
+ & object , redis_ce , & keyword , & kw_len , & arg )
6190
+ == FAILURE )
6191
+ {
6192
+ RETURN_FALSE ;
6193
+ }
6194
+
6195
+ // Validate our sub command keyword, and that we've got proper arguments
6196
+ if (!strncasecmp (keyword , "channels" , sizeof ("channels" ))) {
6197
+ // One (optional) string argument
6198
+ if (arg && Z_TYPE_P (arg ) != IS_STRING ) {
6199
+ RETURN_FALSE ;
6200
+ }
6201
+ type = PUBSUB_CHANNELS ;
6202
+ } else if (!strncasecmp (keyword , "numsub" , sizeof ("numsub" ))) {
6203
+ // One array argument
6204
+ if (ZEND_NUM_ARGS () < 2 || Z_TYPE_P (arg ) != IS_ARRAY ||
6205
+ zend_hash_num_elements (Z_ARRVAL_P (arg ))== 0 )
6206
+ {
6207
+ RETURN_FALSE ;
6208
+ }
6209
+ type = PUBSUB_NUMSUB ;
6210
+ } else if (!strncasecmp (keyword , "numpat" , sizeof ("numpat" ))) {
6211
+ type = PUBSUB_NUMPAT ;
6212
+ } else {
6213
+ // Invalid keyword
6214
+ RETURN_FALSE ;
6215
+ }
6216
+
6217
+ // Grab our socket context object
6218
+ if (redis_sock_get (object , & redis_sock TSRMLS_CC , 0 )< 0 ) {
6219
+ RETURN_FALSE ;
6220
+ }
6221
+
6222
+ // Construct our "PUBSUB" command
6223
+ cmd_len = redis_build_pubsub_cmd (redis_sock , & cmd , type , arg TSRMLS_CC );
6224
+
6225
+ REDIS_PROCESS_REQUEST (redis_sock , cmd , cmd_len );
6226
+
6227
+ if (type == PUBSUB_NUMSUB ) {
6228
+ IF_ATOMIC () {
6229
+ if (redis_sock_read_multibulk_reply_zipped (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock , NULL , NULL )< 0 ) {
6230
+ RETURN_FALSE ;
6231
+ }
6232
+ }
6233
+ REDIS_PROCESS_RESPONSE (redis_sock_read_multibulk_reply_zipped );
6234
+ } else {
6235
+ IF_ATOMIC () {
6236
+ if (redis_read_variant_reply (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock , NULL )< 0 ) {
6237
+ RETURN_FALSE ;
6238
+ }
6239
+ }
6240
+ REDIS_PROCESS_RESPONSE (redis_read_variant_reply );
6241
+ }
6242
+ }
6243
+
6080
6244
// Construct an EVAL or EVALSHA command, with option argument array and number of arguments that are keys parameter
6081
6245
PHPAPI int
6082
6246
redis_build_eval_cmd (RedisSock * redis_sock , char * * ret , char * keyword , char * value , int val_len , zval * args , int keys_count TSRMLS_DC ) {
0 commit comments