@@ -154,6 +154,8 @@ static zend_function_entry redis_functions[] = {
154154 PHP_ME (Redis , bgrewriteaof , NULL , ZEND_ACC_PUBLIC )
155155 PHP_ME (Redis , slaveof , NULL , ZEND_ACC_PUBLIC )
156156 PHP_ME (Redis , object , NULL , ZEND_ACC_PUBLIC )
157+ PHP_ME (Redis , bitop , NULL , ZEND_ACC_PUBLIC )
158+ PHP_ME (Redis , bitcount , NULL , ZEND_ACC_PUBLIC )
157159
158160 PHP_ME (Redis , eval , NULL , ZEND_ACC_PUBLIC )
159161 PHP_ME (Redis , evalsha , NULL , ZEND_ACC_PUBLIC )
@@ -599,6 +601,127 @@ PHPAPI int redis_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) {
599601 return SUCCESS ;
600602}
601603
604+ /* {{{ proto boolean Redis::bitop(string op, string key, ...)
605+ */
606+ PHP_METHOD (Redis , bitop )
607+ {
608+ char * cmd ;
609+ int cmd_len ;
610+
611+ zval * * z_args ;
612+ char * * keys ;
613+ int * keys_len ;
614+ int argc = ZEND_NUM_ARGS (), i ;
615+ RedisSock * redis_sock = NULL ;
616+ smart_str buf = {0 };
617+ int key_free = 0 ;
618+
619+ /* get redis socket */
620+ if (redis_sock_get (getThis (), & redis_sock TSRMLS_CC , 0 ) < 0 ) {
621+ RETURN_FALSE ;
622+ }
623+
624+ /* fetch args */
625+ z_args = emalloc (argc * sizeof (zval * ));
626+ if (zend_get_parameters_array (ht , argc , z_args ) == FAILURE
627+ || argc < 3 /* 3 args min. */
628+ || Z_TYPE_P (z_args [0 ]) != IS_STRING /* operation must be a string. */
629+ ) {
630+ efree (z_args );
631+ RETURN_FALSE ;
632+ }
633+
634+
635+ keys = emalloc (argc * sizeof (char * ));
636+ keys_len = emalloc (argc * sizeof (int ));
637+
638+ /* prefix keys */
639+ for (i = 0 ; i < argc ; ++ i ) {
640+ convert_to_string (z_args [i ]);
641+
642+ keys [i ] = Z_STRVAL_P (z_args [i ]);
643+ keys_len [i ] = Z_STRLEN_P (z_args [i ]);
644+ if (i != 0 )
645+ key_free = redis_key_prefix (redis_sock , & keys [i ], & keys_len [i ] TSRMLS_CC );
646+ }
647+
648+ /* start building the command */
649+ smart_str_appendc (& buf , '*' );
650+ smart_str_append_long (& buf , argc + 1 ); /* +1 for BITOP command */
651+ smart_str_appendl (& buf , _NL , sizeof (_NL ) - 1 );
652+
653+ /* add command name */
654+ smart_str_appendc (& buf , '$' );
655+ smart_str_append_long (& buf , 5 );
656+ smart_str_appendl (& buf , _NL , sizeof (_NL ) - 1 );
657+ smart_str_appendl (& buf , "BITOP" , 5 );
658+ smart_str_appendl (& buf , _NL , sizeof (_NL ) - 1 );
659+
660+ /* add keys */
661+ for (i = 0 ; i < argc ; ++ i ) {
662+ smart_str_appendc (& buf , '$' );
663+ smart_str_append_long (& buf , keys_len [i ]);
664+ smart_str_appendl (& buf , _NL , sizeof (_NL ) - 1 );
665+ smart_str_appendl (& buf , keys [i ], keys_len [i ]);
666+ smart_str_appendl (& buf , _NL , sizeof (_NL ) - 1 );
667+ }
668+ /* end string */
669+ smart_str_0 (& buf );
670+ cmd = buf .c ;
671+ cmd_len = buf .len ;
672+
673+ /* cleanup */
674+ if (key_free )
675+ for (i = 1 ; i < argc ; ++ i ) {
676+ efree (keys [i ]);
677+ }
678+ efree (keys );
679+ efree (keys_len );
680+ efree (z_args );
681+
682+ /* send */
683+ REDIS_PROCESS_REQUEST (redis_sock , cmd , cmd_len );
684+ IF_ATOMIC () {
685+ redis_long_response (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock , NULL , NULL );
686+ }
687+ REDIS_PROCESS_RESPONSE (redis_long_response );
688+ }
689+ /* }}} */
690+
691+ /* {{{ proto boolean Redis::bitcount(string key, [int start], [int end])
692+ */
693+ PHP_METHOD (Redis , bitcount )
694+ {
695+ zval * object ;
696+ RedisSock * redis_sock ;
697+ char * key = NULL , * cmd ;
698+ int key_len , cmd_len , key_free ;
699+ long start = 0 , end = -1 ;
700+
701+ if (zend_parse_method_parameters (ZEND_NUM_ARGS () TSRMLS_CC , getThis (), "Os|ll" ,
702+ & object , redis_ce ,
703+ & key , & key_len , & start , & end ) == FAILURE ) {
704+ RETURN_FALSE ;
705+ }
706+
707+ if (redis_sock_get (object , & redis_sock TSRMLS_CC , 0 ) < 0 ) {
708+ RETURN_FALSE ;
709+ }
710+
711+ /* BITCOUNT key start end */
712+ key_free = redis_key_prefix (redis_sock , & key , & key_len TSRMLS_CC );
713+ cmd_len = redis_cmd_format_static (& cmd , "BITCOUNT" , "sdd" , key , key_len , (int )start , (int )end );
714+ if (key_free ) efree (key );
715+
716+ REDIS_PROCESS_REQUEST (redis_sock , cmd , cmd_len );
717+ IF_ATOMIC () {
718+ redis_long_response (INTERNAL_FUNCTION_PARAM_PASSTHRU , redis_sock , NULL , NULL );
719+ }
720+ REDIS_PROCESS_RESPONSE (redis_long_response );
721+
722+ }
723+ /* }}} */
724+
602725/* {{{ proto boolean Redis::close()
603726 */
604727PHP_METHOD (Redis , close )
@@ -2889,22 +3012,27 @@ PHP_METHOD(Redis, sortDescAlpha)
28893012PHPAPI void generic_expire_cmd (INTERNAL_FUNCTION_PARAMETERS , char * keyword , int keyword_len ) {
28903013 zval * object ;
28913014 RedisSock * redis_sock ;
2892- char * key = NULL , * cmd ;
2893- int key_len , cmd_len , key_free ;
2894- long t ;
3015+ char * key = NULL , * cmd , * t ;
3016+ int key_len , cmd_len , key_free , t_len ;
3017+ int i ;
28953018
2896- if (zend_parse_method_parameters (ZEND_NUM_ARGS () TSRMLS_CC , getThis (), "Osl " ,
3019+ if (zend_parse_method_parameters (ZEND_NUM_ARGS () TSRMLS_CC , getThis (), "Oss " ,
28973020 & object , redis_ce , & key , & key_len ,
2898- & t ) == FAILURE ) {
3021+ & t , & t_len ) == FAILURE ) {
28993022 RETURN_FALSE ;
29003023 }
29013024
29023025 if (redis_sock_get (object , & redis_sock TSRMLS_CC , 0 ) < 0 ) {
29033026 RETURN_FALSE ;
29043027 }
29053028
3029+ /* check that we have a number */
3030+ for (i = 0 ; i < t_len ; ++ i )
3031+ if (t [i ] < '0' || t [i ] > '9' )
3032+ RETURN_FALSE ;
3033+
29063034 key_free = redis_key_prefix (redis_sock , & key , & key_len TSRMLS_CC );
2907- cmd_len = redis_cmd_format_static (& cmd , keyword , "sl " , key , key_len , t );
3035+ cmd_len = redis_cmd_format_static (& cmd , keyword , "ss " , key , key_len , t , t_len );
29083036 if (key_free ) efree (key );
29093037
29103038 REDIS_PROCESS_REQUEST (redis_sock , cmd , cmd_len );
0 commit comments