@@ -278,6 +278,7 @@ static zend_function_entry redis_functions[] = {
278
278
PHP_ME (Redis , isConnected , NULL , ZEND_ACC_PUBLIC )
279
279
280
280
PHP_ME (Redis , wait , NULL , ZEND_ACC_PUBLIC )
281
+ PHP_ME (Redis , pubsub , NULL , ZEND_ACC_PUBLIC )
281
282
282
283
/* aliases */
283
284
PHP_MALIAS (Redis , open , connect , NULL , ZEND_ACC_PUBLIC )
@@ -6132,6 +6133,169 @@ PHP_METHOD(Redis, wait) {
6132
6133
REDIS_PROCESS_RESPONSE (redis_long_response );
6133
6134
}
6134
6135
6136
+ /*
6137
+ * Construct a PUBSUB command
6138
+ */
6139
+ PHPAPI int
6140
+ redis_build_pubsub_cmd (RedisSock * redis_sock , char * * ret , PUBSUB_TYPE type ,
6141
+ zval * arg TSRMLS_CC )
6142
+ {
6143
+ HashTable * ht_chan ;
6144
+ HashPosition ptr ;
6145
+ zval * * z_ele ;
6146
+ char * key ;
6147
+ int cmd_len , key_len , key_free ;
6148
+ smart_str cmd = {0 };
6149
+
6150
+ if (type == PUBSUB_CHANNELS ) {
6151
+ if (arg ) {
6152
+ // Get string argument and length.
6153
+ key = Z_STRVAL_P (arg );
6154
+ key_len = Z_STRLEN_P (arg );
6155
+
6156
+ // Prefix if necissary
6157
+ key_free = redis_key_prefix (redis_sock , & key , & key_len TSRMLS_CC );
6158
+
6159
+ // With a pattern
6160
+ cmd_len = redis_cmd_format_static (ret , "PUBSUB" , "ss" , "CHANNELS" , sizeof ("CHANNELS" )- 1 ,
6161
+ key , key_len );
6162
+
6163
+ // Free the channel name if we prefixed it
6164
+ if (key_free ) efree (key );
6165
+
6166
+ // Return command length
6167
+ return cmd_len ;
6168
+ } else {
6169
+ // No pattern
6170
+ return redis_cmd_format_static (ret , "PUBSUB" , "s" , "CHANNELS" , sizeof ("CHANNELS" )- 1 );
6171
+ }
6172
+ } else if (type == PUBSUB_NUMSUB ) {
6173
+ ht_chan = Z_ARRVAL_P (arg );
6174
+
6175
+ // Add PUBSUB and NUMSUB bits
6176
+ redis_cmd_init_sstr (& cmd , zend_hash_num_elements (ht_chan )+ 1 , "PUBSUB" , sizeof ("PUBSUB" )- 1 );
6177
+ redis_cmd_append_sstr (& cmd , "NUMSUB" , sizeof ("NUMSUB" )- 1 );
6178
+
6179
+ // Iterate our elements
6180
+ for (zend_hash_internal_pointer_reset_ex (ht_chan , & ptr );
6181
+ zend_hash_get_current_data_ex (ht_chan , (void * * )& z_ele , & ptr )== SUCCESS ;
6182
+ zend_hash_move_forward_ex (ht_chan , & ptr ))
6183
+ {
6184
+ char * key ;
6185
+ int key_len , key_free ;
6186
+ zval * z_tmp = NULL ;
6187
+
6188
+ if (Z_TYPE_PP (z_ele ) == IS_STRING ) {
6189
+ key = Z_STRVAL_PP (z_ele );
6190
+ key_len = Z_STRLEN_PP (z_ele );
6191
+ } else {
6192
+ MAKE_STD_ZVAL (z_tmp );
6193
+ * z_tmp = * * z_ele ;
6194
+ zval_copy_ctor (z_tmp );
6195
+ convert_to_string (z_tmp );
6196
+
6197
+ key = Z_STRVAL_P (z_tmp );
6198
+ key_len = Z_STRLEN_P (z_tmp );
6199
+ }
6200
+
6201
+ // Apply prefix if required
6202
+ key_free = redis_key_prefix (redis_sock , & key , & key_len TSRMLS_CC );
6203
+
6204
+ // Append this channel
6205
+ redis_cmd_append_sstr (& cmd , key , key_len );
6206
+
6207
+ // Free key if prefixed
6208
+ if (key_free ) efree (key );
6209
+
6210
+ // Free our temp var if we converted from something other than a string
6211
+ if (z_tmp ) {
6212
+ zval_dtor (z_tmp );
6213
+ efree (z_tmp );
6214
+ z_tmp = NULL ;
6215
+ }
6216
+ }
6217
+
6218
+ // Set return
6219
+ * ret = cmd .c ;
6220
+ return cmd .len ;
6221
+ } else if (type == PUBSUB_NUMPAT ) {
6222
+ return redis_cmd_format_static (ret , "PUBSUB" , "s" , "NUMPAT" , sizeof ("NUMPAT" )- 1 );
6223
+ }
6224
+
6225
+ // Shouldn't ever happen
6226
+ return -1 ;
6227
+ }
6228
+
6229
+ /*
6230
+ * {{{ proto Redis::pubsub("channels", pattern);
6231
+ * proto Redis::pubsub("numsub", Array channels);
6232
+ * proto Redis::pubsub("numpat"); }}}
6233
+ */
6234
+ PHP_METHOD (Redis , pubsub ) {
6235
+ zval * object ;
6236
+ RedisSock * redis_sock ;
6237
+ char * keyword , * cmd ;
6238
+ int kw_len , cmd_len ;
6239
+ PUBSUB_TYPE type ;
6240
+ zval * arg = NULL ;
6241
+
6242
+ // Parse arguments
6243
+ if (zend_parse_method_parameters (ZEND_NUM_ARGS () TSRMLS_CC , getThis (), "Os|z" ,
6244
+ & object , redis_ce , & keyword , & kw_len , & arg )
6245
+ == FAILURE )
6246
+ {
6247
+ RETURN_FALSE ;
6248
+ }
6249
+
6250
+ // Validate our sub command keyword, and that we've got proper arguments
6251
+ if (!strncasecmp (keyword , "channels" , sizeof ("channels" ))) {
6252
+ // One (optional) string argument
6253
+ if (arg && Z_TYPE_P (arg ) != IS_STRING ) {
6254
+ RETURN_FALSE ;
6255
+ }
6256
+ type = PUBSUB_CHANNELS ;
6257
+ } else if (!strncasecmp (keyword , "numsub" , sizeof ("numsub" ))) {
6258
+ // One array argument
6259
+ if (ZEND_NUM_ARGS () < 2 || Z_TYPE_P (arg ) != IS_ARRAY ||
6260
+ zend_hash_num_elements (Z_ARRVAL_P (arg ))== 0 )
6261
+ {
6262
+ RETURN_FALSE ;
6263
+ }
6264
+ type = PUBSUB_NUMSUB ;
6265
+ } else if (!strncasecmp (keyword , "numpat" , sizeof ("numpat" ))) {
6266
+ type = PUBSUB_NUMPAT ;
6267
+ } else {
6268
+ // Invalid keyword
6269
+ RETURN_FALSE ;
6270
+ }
6271
+
6272
+ // Grab our socket context object
6273
+ if (redis_sock_get (object , & redis_sock TSRMLS_CC , 0 )< 0 ) {
6274
+ RETURN_FALSE ;
6275
+ }
6276
+
6277
+ // Construct our "PUBSUB" command
6278
+ cmd_len = redis_build_pubsub_cmd (redis_sock , & cmd , type , arg TSRMLS_CC );
6279
+
6280
+ REDIS_PROCESS_REQUEST (redis_sock , cmd , cmd_len );
6281
+
6282
+ if (type == PUBSUB_NUMSUB ) {
6283
+ IF_ATOMIC () {
6284
+ if (redis_sock_read_multibulk_reply_zipped (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock , NULL , NULL )< 0 ) {
6285
+ RETURN_FALSE ;
6286
+ }
6287
+ }
6288
+ REDIS_PROCESS_RESPONSE (redis_sock_read_multibulk_reply_zipped );
6289
+ } else {
6290
+ IF_ATOMIC () {
6291
+ if (redis_read_variant_reply (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock , NULL )< 0 ) {
6292
+ RETURN_FALSE ;
6293
+ }
6294
+ }
6295
+ REDIS_PROCESS_RESPONSE (redis_read_variant_reply );
6296
+ }
6297
+ }
6298
+
6135
6299
// Construct an EVAL or EVALSHA command, with option argument array and number of arguments that are keys parameter
6136
6300
PHPAPI int
6137
6301
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