@@ -206,7 +206,9 @@ static zend_function_entry redis_functions[] = {
206
206
207
207
PHP_ME (Redis , publish , NULL , ZEND_ACC_PUBLIC )
208
208
PHP_ME (Redis , subscribe , NULL , ZEND_ACC_PUBLIC )
209
+ PHP_ME (Redis , psubscribe , NULL , ZEND_ACC_PUBLIC )
209
210
PHP_ME (Redis , unsubscribe , NULL , ZEND_ACC_PUBLIC )
211
+ PHP_ME (Redis , punsubscribe , NULL , ZEND_ACC_PUBLIC )
210
212
211
213
PHP_ME (Redis , time , NULL , ZEND_ACC_PUBLIC )
212
214
@@ -5274,24 +5276,19 @@ PHP_METHOD(Redis, publish)
5274
5276
REDIS_PROCESS_RESPONSE (redis_long_response );
5275
5277
}
5276
5278
5277
- /*
5278
- subscribe channel_1 channel_2 ... channel_n
5279
- subscribe(array(channel_1, channel_2, ..., channel_n), callback)
5280
- */
5281
- PHP_METHOD (Redis , subscribe )
5279
+ PHPAPI void generic_subscribe_cmd (INTERNAL_FUNCTION_PARAMETERS , char * sub_cmd )
5282
5280
{
5283
5281
zval * z_callback ,* object , * array , * * data ;
5284
5282
HashTable * arr_hash ;
5285
5283
HashPosition pointer ;
5286
5284
RedisSock * redis_sock ;
5287
5285
char * cmd = "" , * old_cmd = NULL , * callback_ft_name ;
5288
5286
int cmd_len , array_count , callback_ft_name_len ;
5289
-
5290
5287
zval * z_tab , * * tmp ;
5291
5288
char * type_response ;
5292
5289
5293
5290
int callback_type = 0 ;
5294
- zval * z_o , * z_fun = NULL ,* z_ret , * z_args [3 ];
5291
+ zval * z_o , * z_fun = NULL ,* z_ret , * z_args [4 ];
5295
5292
char * method_name ;
5296
5293
5297
5294
if (zend_parse_method_parameters (ZEND_NUM_ARGS () TSRMLS_CC , getThis (), "Oaz|z" ,
@@ -5327,7 +5324,7 @@ PHP_METHOD(Redis, subscribe)
5327
5324
}
5328
5325
5329
5326
old_cmd = cmd ;
5330
- cmd_len = spprintf (& cmd , 0 , "SUBSCRIBE %s\r\n" , cmd );
5327
+ cmd_len = spprintf (& cmd , 0 , "%s %s\r\n" , sub_cmd , cmd );
5331
5328
efree (old_cmd );
5332
5329
if (redis_sock_write (redis_sock , cmd , cmd_len TSRMLS_CC ) < 0 ) {
5333
5330
efree (cmd );
@@ -5344,7 +5341,7 @@ PHP_METHOD(Redis, subscribe)
5344
5341
5345
5342
if (zend_hash_index_find (Z_ARRVAL_P (z_tab ), 0 , (void * * )& tmp ) == SUCCESS ) {
5346
5343
type_response = Z_STRVAL_PP (tmp );
5347
- if (strcmp (type_response , "subscribe" ) != 0 ) {
5344
+ if (strcmp (type_response , sub_cmd ) != 0 ) {
5348
5345
efree (tmp );
5349
5346
efree (z_tab );
5350
5347
RETURN_FALSE ;
@@ -5385,42 +5382,66 @@ PHP_METHOD(Redis, subscribe)
5385
5382
/* Multibulk Response, format : {message type, originating channel, message payload} */
5386
5383
while (1 ) {
5387
5384
/* call the callback with this z_tab in argument */
5388
- zval * * type , * * channel , * * data ;
5385
+ zval * * type , * * channel , * * pattern , * * data ;
5389
5386
z_tab = redis_sock_read_multibulk_reply_zval (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock );
5387
+ int is_pmsg , tab_idx = 1 ;
5390
5388
5391
5389
if (z_tab == NULL || Z_TYPE_P (z_tab ) != IS_ARRAY ) {
5392
5390
//ERROR
5393
5391
break ;
5394
5392
}
5395
5393
5396
- if (zend_hash_index_find (Z_ARRVAL_P (z_tab ), 0 , (void * * )& type ) == FAILURE ) {
5394
+ if (zend_hash_index_find (Z_ARRVAL_P (z_tab ), 0 , (void * * )& type ) == FAILURE || Z_TYPE_PP ( type ) != IS_STRING ) {
5397
5395
break ;
5398
5396
}
5399
- if (zend_hash_index_find (Z_ARRVAL_P (z_tab ), 1 , (void * * )& channel ) == FAILURE ) {
5397
+
5398
+ // Make sure we have a message or pmessage
5399
+ if (!strncmp (Z_STRVAL_PP (type ), "message" , 7 ) || !strncmp (Z_STRVAL_PP (type ), "pmessage" , 8 )) {
5400
+ // Is this a pmessage
5401
+ is_pmsg = * Z_STRVAL_PP (type ) == 'p' ;
5402
+ } else {
5403
+ continue ; // It's not a message or pmessage
5404
+ }
5405
+
5406
+ // If this is a pmessage, we'll want to extract the pattern first
5407
+ if (is_pmsg ) {
5408
+ // Extract pattern
5409
+ if (zend_hash_index_find (Z_ARRVAL_P (z_tab ), tab_idx ++ , (void * * )& pattern ) == FAILURE ) {
5410
+ break ;
5411
+ }
5412
+ }
5413
+
5414
+ // Extract channel and data
5415
+ if (zend_hash_index_find (Z_ARRVAL_P (z_tab ), tab_idx ++ , (void * * )& channel ) == FAILURE ) {
5400
5416
break ;
5401
- }
5402
- if (zend_hash_index_find (Z_ARRVAL_P (z_tab ), 2 , (void * * )& data ) == FAILURE ) {
5417
+ }
5418
+ if (zend_hash_index_find (Z_ARRVAL_P (z_tab ), tab_idx ++ , (void * * )& data ) == FAILURE ) {
5403
5419
break ;
5404
5420
}
5405
5421
5406
- if (Z_TYPE_PP (type ) == IS_STRING && strncmp (Z_STRVAL_PP (type ), "message" , 7 ) != 0 ) {
5407
- continue ; /* only forwarding published messages */
5408
- }
5409
-
5422
+ // Always pass the Redis object through
5410
5423
z_args [0 ] = getThis ();
5411
- z_args [1 ] = * channel ;
5412
- z_args [2 ] = * data ;
5424
+
5425
+ // Set up our callback args depending on the message type
5426
+ if (is_pmsg ) {
5427
+ z_args [1 ] = * pattern ;
5428
+ z_args [2 ] = * channel ;
5429
+ z_args [3 ] = * data ;
5430
+ } else {
5431
+ z_args [1 ] = * channel ;
5432
+ z_args [2 ] = * data ;
5433
+ }
5413
5434
5414
5435
switch (callback_type ) {
5415
5436
case R_SUB_CALLBACK_CLASS_TYPE :
5416
5437
MAKE_STD_ZVAL (z_ret );
5417
- call_user_function (& redis_ce -> function_table , & z_o , z_fun , z_ret , 3 , z_args TSRMLS_CC );
5438
+ call_user_function (& redis_ce -> function_table , & z_o , z_fun , z_ret , tab_idx , z_args TSRMLS_CC );
5418
5439
efree (z_ret );
5419
5440
break ;
5420
5441
5421
5442
case R_SUB_CALLBACK_FT_TYPE :
5422
5443
MAKE_STD_ZVAL (z_ret );
5423
- call_user_function (EG (function_table ), NULL , z_fun , z_ret , 3 , z_args TSRMLS_CC );
5444
+ call_user_function (EG (function_table ), NULL , z_fun , z_ret , tab_idx , z_args TSRMLS_CC );
5424
5445
efree (z_ret );
5425
5446
break ;
5426
5447
}
@@ -5433,9 +5454,22 @@ PHP_METHOD(Redis, subscribe)
5433
5454
efree (z_fun );
5434
5455
}
5435
5456
5457
+ /* {{{ proto void Redis::psubscribe(Array(channel1, channel2, ... channelN))
5458
+ */
5459
+ PHP_METHOD (Redis , psubscribe )
5460
+ {
5461
+ generic_subscribe_cmd (INTERNAL_FUNCTION_PARAM_PASSTHRU , "psubscribe" );
5462
+ }
5463
+
5464
+ /* {{{ proto void Redis::psubscribe(Array(channel1, channel2, ... channelN))
5465
+ */
5466
+ PHP_METHOD (Redis , subscribe ) {
5467
+ generic_subscribe_cmd (INTERNAL_FUNCTION_PARAM_PASSTHRU , "subscribe" );
5468
+ }
5469
+
5436
5470
/**
5437
- * unsubscribe channel_0 channel_1 ... channel_n
5438
- * unsubscribe(array(channel_0, channel_1, ..., channel_n))
5471
+ * [p] unsubscribe channel_0 channel_1 ... channel_n
5472
+ * [p] unsubscribe(array(channel_0, channel_1, ..., channel_n))
5439
5473
* response format :
5440
5474
* array(
5441
5475
* channel_0 => TRUE|FALSE,
@@ -5445,7 +5479,7 @@ PHP_METHOD(Redis, subscribe)
5445
5479
* );
5446
5480
**/
5447
5481
5448
- PHP_METHOD ( Redis , unsubscribe )
5482
+ PHPAPI void generic_unsubscribe_cmd ( INTERNAL_FUNCTION_PARAMETERS , char * unsub_cmd )
5449
5483
{
5450
5484
zval * object , * array , * * data ;
5451
5485
HashTable * arr_hash ;
@@ -5490,7 +5524,7 @@ PHP_METHOD(Redis, unsubscribe)
5490
5524
}
5491
5525
5492
5526
old_cmd = cmd ;
5493
- cmd_len = spprintf (& cmd , 0 , "UNSUBSCRIBE %s\r\n" , cmd );
5527
+ cmd_len = spprintf (& cmd , 0 , "%s %s\r\n" , unsub_cmd , cmd );
5494
5528
efree (old_cmd );
5495
5529
5496
5530
if (redis_sock_write (redis_sock , cmd , cmd_len TSRMLS_CC ) < 0 ) {
@@ -5520,6 +5554,16 @@ PHP_METHOD(Redis, unsubscribe)
5520
5554
}
5521
5555
}
5522
5556
5557
+ PHP_METHOD (Redis , unsubscribe )
5558
+ {
5559
+ generic_unsubscribe_cmd (INTERNAL_FUNCTION_PARAM_PASSTHRU , "UNSUBSCRIBE" );
5560
+ }
5561
+
5562
+ PHP_METHOD (Redis , punsubscribe )
5563
+ {
5564
+ generic_unsubscribe_cmd (INTERNAL_FUNCTION_PARAM_PASSTHRU , "PUNSUBSCRIBE" );
5565
+ }
5566
+
5523
5567
/* {{{ proto string Redis::bgrewriteaof()
5524
5568
*/
5525
5569
PHP_METHOD (Redis , bgrewriteaof )
0 commit comments