1 #include "php.h"
2 #include "php_ini.h"
3 
4 #ifndef REDIS_COMMON_H
5 #define REDIS_COMMON_H
6 
7 #define PHPREDIS_NOTUSED(v) ((void)v)
8 
9 #include "zend_llist.h"
10 #include <ext/standard/php_var.h>
11 #include <ext/standard/php_math.h>
12 #include <zend_smart_str.h>
13 #include <ext/standard/php_smart_string.h>
14 
15 #define PHPREDIS_GET_OBJECT(class_entry, o) (class_entry *)((char *)o - XtOffsetOf(class_entry, std))
16 #define PHPREDIS_ZVAL_GET_OBJECT(class_entry, z) PHPREDIS_GET_OBJECT(class_entry, Z_OBJ_P(z))
17 
18 /* NULL check so Eclipse doesn't go crazy */
19 #ifndef NULL
20 #define NULL   ((void *) 0)
21 #endif
22 
23 #include "backoff.h"
24 
25 typedef enum {
26     REDIS_SOCK_STATUS_FAILED = -1,
27     REDIS_SOCK_STATUS_DISCONNECTED,
28     REDIS_SOCK_STATUS_CONNECTED,
29     REDIS_SOCK_STATUS_READY
30 } redis_sock_status;
31 
32 #define _NL "\r\n"
33 
34 /* properties */
35 #define REDIS_NOT_FOUND 0
36 #define REDIS_STRING    1
37 #define REDIS_SET       2
38 #define REDIS_LIST      3
39 #define REDIS_ZSET      4
40 #define REDIS_HASH      5
41 #define REDIS_STREAM    6
42 
43 #ifdef PHP_WIN32
44 #define PHP_REDIS_API __declspec(dllexport)
45 #define phpredis_atoi64(p) _atoi64((p))
46 #else
47 #define PHP_REDIS_API
48 #define phpredis_atoi64(p) atoll((p))
49 #endif
50 
51 /* reply types */
52 typedef enum _REDIS_REPLY_TYPE {
53     TYPE_EOF       = -1,
54     TYPE_LINE      = '+',
55     TYPE_INT       = ':',
56     TYPE_ERR       = '-',
57     TYPE_BULK      = '$',
58     TYPE_MULTIBULK = '*'
59 } REDIS_REPLY_TYPE;
60 
61 /* SCAN variants */
62 typedef enum _REDIS_SCAN_TYPE {
63     TYPE_SCAN,
64     TYPE_SSCAN,
65     TYPE_HSCAN,
66     TYPE_ZSCAN
67 } REDIS_SCAN_TYPE;
68 
69 /* PUBSUB subcommands */
70 typedef enum _PUBSUB_TYPE {
71     PUBSUB_CHANNELS,
72     PUBSUB_NUMSUB,
73     PUBSUB_NUMPAT
74 } PUBSUB_TYPE;
75 
76 /* options */
77 #define REDIS_OPT_SERIALIZER         1
78 #define REDIS_OPT_PREFIX             2
79 #define REDIS_OPT_READ_TIMEOUT       3
80 #define REDIS_OPT_SCAN               4
81 #define REDIS_OPT_FAILOVER           5
82 #define REDIS_OPT_TCP_KEEPALIVE      6
83 #define REDIS_OPT_COMPRESSION        7
84 #define REDIS_OPT_REPLY_LITERAL      8
85 #define REDIS_OPT_COMPRESSION_LEVEL  9
86 #define REDIS_OPT_NULL_MBULK_AS_NULL 10
87 #define REDIS_OPT_MAX_RETRIES        11
88 #define REDIS_OPT_BACKOFF_ALGORITHM  12
89 #define REDIS_OPT_BACKOFF_BASE       13
90 #define REDIS_OPT_BACKOFF_CAP        14
91 
92 /* cluster options */
93 #define REDIS_FAILOVER_NONE              0
94 #define REDIS_FAILOVER_ERROR             1
95 #define REDIS_FAILOVER_DISTRIBUTE        2
96 #define REDIS_FAILOVER_DISTRIBUTE_SLAVES 3
97 /* serializers */
98 typedef enum {
99     REDIS_SERIALIZER_NONE,
100     REDIS_SERIALIZER_PHP,
101     REDIS_SERIALIZER_IGBINARY,
102     REDIS_SERIALIZER_MSGPACK,
103     REDIS_SERIALIZER_JSON
104 } redis_serializer;
105 /* compression */
106 #define REDIS_COMPRESSION_NONE 0
107 #define REDIS_COMPRESSION_LZF  1
108 #define REDIS_COMPRESSION_ZSTD 2
109 #define REDIS_COMPRESSION_LZ4  3
110 
111 /* SCAN options */
112 #define REDIS_SCAN_NORETRY 0
113 #define REDIS_SCAN_RETRY   1
114 #define REDIS_SCAN_PREFIX  2
115 #define REDIS_SCAN_NOPREFIX 3
116 
117 /* BACKOFF_ALGORITHM options */
118 #define REDIS_BACKOFF_ALGORITHMS                    7
119 #define REDIS_BACKOFF_ALGORITHM_DEFAULT             0
120 #define REDIS_BACKOFF_ALGORITHM_DECORRELATED_JITTER 1
121 #define REDIS_BACKOFF_ALGORITHM_FULL_JITTER         2
122 #define REDIS_BACKOFF_ALGORITHM_EQUAL_JITTER        3
123 #define REDIS_BACKOFF_ALGORITHM_EXPONENTIAL         4
124 #define REDIS_BACKOFF_ALGORITHM_UNIFORM             5
125 #define REDIS_BACKOFF_ALGORITHM_CONSTANT            6
126 
127 /* GETBIT/SETBIT offset range limits */
128 #define BITOP_MIN_OFFSET 0
129 #define BITOP_MAX_OFFSET 4294967295U
130 
131 /* Transaction modes */
132 #define ATOMIC   0
133 #define MULTI    1
134 #define PIPELINE 2
135 
136 #define PHPREDIS_DEBUG_LOGGING 0
137 
138 #if PHPREDIS_DEBUG_LOGGING == 1
139 #define redisDbgFmt(fmt, ...) \
140     php_printf("%s:%d:%s(): " fmt "\n", __FILE__, __LINE__, __func__, __VA_ARGS__)
141 #define redisDbgStr(str) phpredisDebugFmt("%s", str)
142 #else
143 #define redisDbgFmt(fmt, ...) ((void)0)
144 #define redisDbgStr(str) ((void)0)
145 #endif
146 
147 #define IS_ATOMIC(redis_sock) (redis_sock->mode == ATOMIC)
148 #define IS_MULTI(redis_sock) (redis_sock->mode & MULTI)
149 #define IS_PIPELINE(redis_sock) (redis_sock->mode & PIPELINE)
150 
151 #define PIPELINE_ENQUEUE_COMMAND(cmd, cmd_len) do { \
152     if (redis_sock->pipeline_cmd == NULL) { \
153         redis_sock->pipeline_cmd = zend_string_init(cmd, cmd_len, 0); \
154     } else { \
155         size_t pipeline_len = ZSTR_LEN(redis_sock->pipeline_cmd); \
156         redis_sock->pipeline_cmd = zend_string_realloc(redis_sock->pipeline_cmd, pipeline_len + cmd_len, 0); \
157         memcpy(&ZSTR_VAL(redis_sock->pipeline_cmd)[pipeline_len], cmd, cmd_len); \
158     } \
159 } while (0)
160 
161 #define SOCKET_WRITE_COMMAND(redis_sock, cmd, cmd_len) \
162     if(redis_sock_write(redis_sock, cmd, cmd_len) < 0) { \
163     efree(cmd); \
164     RETURN_FALSE; \
165 }
166 
167 #define REDIS_SAVE_CALLBACK(callback, closure_context) do { \
168     fold_item *fi = malloc(sizeof(fold_item)); \
169     fi->fun = callback; \
170     fi->ctx = closure_context; \
171     fi->next = NULL; \
172     if (redis_sock->current) { \
173         redis_sock->current->next = fi; \
174     } \
175     redis_sock->current = fi; \
176     if (NULL == redis_sock->head) { \
177         redis_sock->head = redis_sock->current; \
178     } \
179 } while (0)
180 
181 #define REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len) \
182     if (IS_PIPELINE(redis_sock)) { \
183         PIPELINE_ENQUEUE_COMMAND(cmd, cmd_len); \
184     } else { \
185         SOCKET_WRITE_COMMAND(redis_sock, cmd, cmd_len); \
186     } \
187     efree(cmd);
188 
189 #define REDIS_PROCESS_RESPONSE_CLOSURE(function, closure_context) \
190     if (!IS_PIPELINE(redis_sock)) { \
191         if (redis_response_enqueued(redis_sock) != SUCCESS) { \
192             RETURN_FALSE; \
193         } \
194     } \
195     REDIS_SAVE_CALLBACK(function, closure_context); \
196     RETURN_ZVAL(getThis(), 1, 0); \
197 
198 #define REDIS_PROCESS_RESPONSE(function) else { \
199     REDIS_PROCESS_RESPONSE_CLOSURE(function, NULL) \
200 }
201 
202 /* Clear redirection info */
203 #define REDIS_MOVED_CLEAR(redis_sock) \
204     redis_sock->redir_slot = 0; \
205     redis_sock->redir_port = 0; \
206     redis_sock->redir_type = MOVED_NONE; \
207 
208 /* Process a command assuming our command where our command building
209  * function is redis_<cmdname>_cmd */
210 #define REDIS_PROCESS_CMD(cmdname, resp_func) \
211     RedisSock *redis_sock; char *cmd; int cmd_len; void *ctx=NULL; \
212     if ((redis_sock = redis_sock_get(getThis(), 0)) == NULL || \
213        redis_##cmdname##_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU,redis_sock, \
214                              &cmd, &cmd_len, NULL, &ctx)==FAILURE) { \
215             RETURN_FALSE; \
216     } \
217     REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len); \
218     if (IS_ATOMIC(redis_sock)) { \
219         resp_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL, ctx); \
220     } else { \
221         REDIS_PROCESS_RESPONSE_CLOSURE(resp_func, ctx) \
222     }
223 
224 /* Process a command but with a specific command building function
225  * and keyword which is passed to us*/
226 #define REDIS_PROCESS_KW_CMD(kw, cmdfunc, resp_func) \
227     RedisSock *redis_sock; char *cmd; int cmd_len; void *ctx=NULL; \
228     if ((redis_sock = redis_sock_get(getThis(), 0)) == NULL || \
229        cmdfunc(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, kw, &cmd, \
230                &cmd_len, NULL, &ctx)==FAILURE) { \
231             RETURN_FALSE; \
232     } \
233     REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len); \
234     if (IS_ATOMIC(redis_sock)) { \
235         resp_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL, ctx); \
236     } else { \
237         REDIS_PROCESS_RESPONSE_CLOSURE(resp_func, ctx) \
238     }
239 
240 /* Case sensitive compare against compile-time static string */
241 #define REDIS_STRCMP_STATIC(s, len, sstr) \
242     (len == sizeof(sstr) - 1 && !strncmp(s, sstr, len))
243 
244 /* Case insensitive compare against compile-time static string */
245 #define REDIS_STRICMP_STATIC(s, len, sstr) \
246     (len == sizeof(sstr) - 1 && !strncasecmp(s, sstr, len))
247 
248 /* Test if a zval is a string and (case insensitive) matches a static string */
249 #define ZVAL_STRICMP_STATIC(zv, sstr) \
250     REDIS_STRICMP_STATIC(Z_STRVAL_P(zv), Z_STRLEN_P(zv), sstr)
251 
252 /* Case insensitive compare of a zend_string to a static string */
253 #define ZSTR_STRICMP_STATIC(zs, sstr) \
254     REDIS_STRICMP_STATIC(ZSTR_VAL(zs), ZSTR_LEN(zs), sstr)
255 
256 /* Extended SET argument detection */
257 #define ZSTR_IS_EX_ARG(zs) ZSTR_STRICMP_STATIC(zs, "EX")
258 #define ZSTR_IS_PX_ARG(zs) ZSTR_STRICMP_STATIC(zs, "PX")
259 #define ZSTR_IS_NX_ARG(zs) ZSTR_STRICMP_STATIC(zs, "NX")
260 #define ZSTR_IS_XX_ARG(zs) ZSTR_STRICMP_STATIC(zs, "XX")
261 
262 #define ZVAL_IS_NX_XX_ARG(zv) (ZVAL_STRICMP_STATIC(zv, "NX") || ZVAL_STRICMP_STATIC(zv, "XX"))
263 #define ZSTR_IS_EX_PX_ARG(a) (ZSTR_IS_EX_ARG(a) || ZSTR_IS_PX_ARG(a))
264 
265 /* Given a string and length, validate a zRangeByLex argument.  The semantics
266  * here are that the argument must start with '(' or '[' or be just the char
267  * '+' or '-' */
268 #define IS_LEX_ARG(s,l) \
269     (l>0 && (*s=='(' || *s=='[' || (l==1 && (*s=='+' || *s=='-'))))
270 
271 #define REDIS_ENABLE_MODE(redis_sock, m) (redis_sock->mode |= m)
272 #define REDIS_DISABLE_MODE(redis_sock, m) (redis_sock->mode &= ~m)
273 
274 /* HOST_NAME_MAX doesn't exist everywhere */
275 #ifndef HOST_NAME_MAX
276     #if defined(_POSIX_HOST_NAME_MAX)
277         #define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
278     #elif defined(MAXHOSTNAMELEN)
279         #define HOST_NAME_MAX MAXHOSTNAMELEN
280     #else
281         #define HOST_NAME_MAX 255
282     #endif
283 #endif
284 
285 /* {{{ struct RedisSock */
286 typedef struct {
287     php_stream          *stream;
288     php_stream_context  *stream_ctx;
289     zend_string         *host;
290     int                 port;
291     zend_string         *user;
292     zend_string         *pass;
293     double              timeout;
294     double              read_timeout;
295     long                retry_interval;
296     int                 max_retries;
297     struct RedisBackoff backoff;
298     redis_sock_status   status;
299     int                 persistent;
300     int                 watching;
301     zend_string         *persistent_id;
302 
303     redis_serializer    serializer;
304     int                 compression;
305     int                 compression_level;
306     long                dbNumber;
307 
308     zend_string         *prefix;
309 
310     short               mode;
311     struct fold_item    *head;
312     struct fold_item    *current;
313 
314     zend_string         *pipeline_cmd;
315 
316     zend_string         *err;
317 
318     int                 scan;
319 
320     int                 readonly;
321     int                 reply_literal;
322     int                 null_mbulk_as_null;
323     int                 tcp_keepalive;
324 } RedisSock;
325 /* }}} */
326 
327 /* Redis response handler function callback prototype */
328 typedef void (*ResultCallback)(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
329 typedef int (*FailableResultCallback)(INTERNAL_FUNCTION_PARAMETERS, RedisSock*, zval*, void*);
330 
331 typedef struct fold_item {
332     FailableResultCallback fun;
333     void *ctx;
334     struct fold_item *next;
335 } fold_item;
336 
337 typedef struct {
338     zend_llist list;
339     int nb_active;
340 } ConnectionPool;
341 
342 typedef struct {
343     RedisSock *sock;
344     zend_object std;
345 } redis_object;
346 
347 /** Argument info for any function expecting 0 args */
348 ZEND_BEGIN_ARG_INFO_EX(arginfo_void, 0, 0, 0)
349 ZEND_END_ARG_INFO()
350 
351 ZEND_BEGIN_ARG_INFO_EX(arginfo_key, 0, 0, 1)
352     ZEND_ARG_INFO(0, key)
353 ZEND_END_ARG_INFO()
354 
355 ZEND_BEGIN_ARG_INFO_EX(arginfo_value, 0, 0, 1)
356     ZEND_ARG_INFO(0, value)
357 ZEND_END_ARG_INFO()
358 
359 ZEND_BEGIN_ARG_INFO_EX(arginfo_key_value, 0, 0, 2)
360     ZEND_ARG_INFO(0, key)
361     ZEND_ARG_INFO(0, value)
362 ZEND_END_ARG_INFO()
363 
364 ZEND_BEGIN_ARG_INFO_EX(arginfo_key_expire_value, 0, 0, 3)
365     ZEND_ARG_INFO(0, key)
366     ZEND_ARG_INFO(0, expire)
367     ZEND_ARG_INFO(0, value)
368 ZEND_END_ARG_INFO()
369 
370 ZEND_BEGIN_ARG_INFO_EX(arginfo_key_newkey, 0, 0, 2)
371     ZEND_ARG_INFO(0, key)
372     ZEND_ARG_INFO(0, newkey)
373 ZEND_END_ARG_INFO()
374 
375 ZEND_BEGIN_ARG_INFO_EX(arginfo_pairs, 0, 0, 1)
376     ZEND_ARG_ARRAY_INFO(0, pairs, 0)
377 ZEND_END_ARG_INFO()
378 
379 ZEND_BEGIN_ARG_INFO_EX(arginfo_nkeys, 0, 0, 1)
380     ZEND_ARG_INFO(0, key)
381     ZEND_ARG_VARIADIC_INFO(0, other_keys)
382 ZEND_END_ARG_INFO()
383 
384 ZEND_BEGIN_ARG_INFO_EX(arginfo_dst_nkeys, 0, 0, 2)
385     ZEND_ARG_INFO(0, dst)
386     ZEND_ARG_INFO(0, key)
387     ZEND_ARG_VARIADIC_INFO(0, other_keys)
388 ZEND_END_ARG_INFO()
389 
390 ZEND_BEGIN_ARG_INFO_EX(arginfo_key_min_max, 0, 0, 3)
391     ZEND_ARG_INFO(0, key)
392     ZEND_ARG_INFO(0, min)
393     ZEND_ARG_INFO(0, max)
394 ZEND_END_ARG_INFO()
395 
396 ZEND_BEGIN_ARG_INFO_EX(arginfo_key_member, 0, 0, 2)
397     ZEND_ARG_INFO(0, key)
398     ZEND_ARG_INFO(0, member)
399 ZEND_END_ARG_INFO()
400 
401 ZEND_BEGIN_ARG_INFO_EX(arginfo_key_member_value, 0, 0, 3)
402     ZEND_ARG_INFO(0, key)
403     ZEND_ARG_INFO(0, member)
404     ZEND_ARG_INFO(0, value)
405 ZEND_END_ARG_INFO()
406 
407 ZEND_BEGIN_ARG_INFO_EX(arginfo_key_members, 0, 0, 2)
408     ZEND_ARG_INFO(0, key)
409     ZEND_ARG_INFO(0, member)
410     ZEND_ARG_VARIADIC_INFO(0, other_members)
411 ZEND_END_ARG_INFO()
412 
413 ZEND_BEGIN_ARG_INFO_EX(arginfo_key_timestamp, 0, 0, 2)
414     ZEND_ARG_INFO(0, key)
415     ZEND_ARG_INFO(0, timestamp)
416 ZEND_END_ARG_INFO()
417 
418 ZEND_BEGIN_ARG_INFO_EX(arginfo_key_offset, 0, 0, 2)
419     ZEND_ARG_INFO(0, key)
420     ZEND_ARG_INFO(0, offset)
421 ZEND_END_ARG_INFO()
422 
423 ZEND_BEGIN_ARG_INFO_EX(arginfo_key_offset_value, 0, 0, 3)
424     ZEND_ARG_INFO(0, key)
425     ZEND_ARG_INFO(0, offset)
426     ZEND_ARG_INFO(0, value)
427 ZEND_END_ARG_INFO()
428 
429 ZEND_BEGIN_ARG_INFO_EX(arginfo_swapdb, 0, 0, 2)
430     ZEND_ARG_INFO(0, srcdb)
431     ZEND_ARG_INFO(0, dstdb)
432 ZEND_END_ARG_INFO()
433 
434 ZEND_BEGIN_ARG_INFO_EX(arginfo_key_start_end, 0, 0, 3)
435     ZEND_ARG_INFO(0, key)
436     ZEND_ARG_INFO(0, start)
437     ZEND_ARG_INFO(0, end)
438 ZEND_END_ARG_INFO()
439 
440 ZEND_BEGIN_ARG_INFO_EX(arginfo_echo, 0, 0, 1)
441     ZEND_ARG_INFO(0, msg)
442 ZEND_END_ARG_INFO()
443 
444 ZEND_BEGIN_ARG_INFO_EX(arginfo_expire, 0, 0, 2)
445     ZEND_ARG_INFO(0, key)
446     ZEND_ARG_INFO(0, timeout)
447 ZEND_END_ARG_INFO()
448 
449 ZEND_BEGIN_ARG_INFO_EX(arginfo_set, 0, 0, 2)
450     ZEND_ARG_INFO(0, key)
451     ZEND_ARG_INFO(0, value)
452     ZEND_ARG_INFO(0, opts)
453 ZEND_END_ARG_INFO()
454 
455 ZEND_BEGIN_ARG_INFO_EX(arginfo_lset, 0, 0, 3)
456     ZEND_ARG_INFO(0, key)
457     ZEND_ARG_INFO(0, index)
458     ZEND_ARG_INFO(0, value)
459 ZEND_END_ARG_INFO()
460 
461 ZEND_BEGIN_ARG_INFO_EX(arginfo_blrpop, 0, 0, 2)
462     ZEND_ARG_INFO(0, key)
463     ZEND_ARG_INFO(0, timeout_or_key)
464     ZEND_ARG_VARIADIC_INFO(0, extra_args)
465 ZEND_END_ARG_INFO()
466 
467 ZEND_BEGIN_ARG_INFO_EX(arginfo_linsert, 0, 0, 4)
468     ZEND_ARG_INFO(0, key)
469     ZEND_ARG_INFO(0, position)
470     ZEND_ARG_INFO(0, pivot)
471     ZEND_ARG_INFO(0, value)
472 ZEND_END_ARG_INFO()
473 
474 ZEND_BEGIN_ARG_INFO_EX(arginfo_lindex, 0, 0, 2)
475     ZEND_ARG_INFO(0, key)
476     ZEND_ARG_INFO(0, index)
477 ZEND_END_ARG_INFO()
478 
479 ZEND_BEGIN_ARG_INFO_EX(arginfo_brpoplpush, 0, 0, 3)
480     ZEND_ARG_INFO(0, src)
481     ZEND_ARG_INFO(0, dst)
482     ZEND_ARG_INFO(0, timeout)
483 ZEND_END_ARG_INFO()
484 
485 ZEND_BEGIN_ARG_INFO_EX(arginfo_rpoplpush, 0, 0, 2)
486     ZEND_ARG_INFO(0, src)
487     ZEND_ARG_INFO(0, dst)
488 ZEND_END_ARG_INFO()
489 
490 ZEND_BEGIN_ARG_INFO_EX(arginfo_sadd_array, 0, 0, 2)
491     ZEND_ARG_INFO(0, key)
492     ZEND_ARG_ARRAY_INFO(0, options, 0)
493 ZEND_END_ARG_INFO()
494 
495 ZEND_BEGIN_ARG_INFO_EX(arginfo_srand_member, 0, 0, 1)
496     ZEND_ARG_INFO(0, key)
497     ZEND_ARG_INFO(0, count)
498 ZEND_END_ARG_INFO()
499 
500 ZEND_BEGIN_ARG_INFO_EX(arginfo_zadd, 0, 0, 3)
501     ZEND_ARG_INFO(0, key)
502     ZEND_ARG_INFO(0, score)
503     ZEND_ARG_INFO(0, value)
504     ZEND_ARG_VARIADIC_INFO(0, extra_args)
505 ZEND_END_ARG_INFO()
506 
507 ZEND_BEGIN_ARG_INFO_EX(arginfo_zincrby, 0, 0, 3)
508     ZEND_ARG_INFO(0, key)
509     ZEND_ARG_INFO(0, value)
510     ZEND_ARG_INFO(0, member)
511 ZEND_END_ARG_INFO()
512 
513 ZEND_BEGIN_ARG_INFO_EX(arginfo_hmget, 0, 0, 2)
514     ZEND_ARG_INFO(0, key)
515     ZEND_ARG_ARRAY_INFO(0, keys, 0)
516 ZEND_END_ARG_INFO()
517 
518 ZEND_BEGIN_ARG_INFO_EX(arginfo_hmset, 0, 0, 2)
519     ZEND_ARG_INFO(0, key)
520     ZEND_ARG_ARRAY_INFO(0, pairs, 0)
521 ZEND_END_ARG_INFO()
522 
523 ZEND_BEGIN_ARG_INFO_EX(arginfo_bitop, 0, 0, 3)
524     ZEND_ARG_INFO(0, operation)
525     ZEND_ARG_INFO(0, ret_key)
526     ZEND_ARG_INFO(0, key)
527     ZEND_ARG_VARIADIC_INFO(0, other_keys)
528 ZEND_END_ARG_INFO()
529 
530 ZEND_BEGIN_ARG_INFO_EX(arginfo_bitpos, 0, 0, 2)
531     ZEND_ARG_INFO(0, key)
532     ZEND_ARG_INFO(0, bit)
533     ZEND_ARG_INFO(0, start)
534     ZEND_ARG_INFO(0, end)
535 ZEND_END_ARG_INFO()
536 
537 ZEND_BEGIN_ARG_INFO_EX(arginfo_ltrim, 0, 0, 3)
538     ZEND_ARG_INFO(0, key)
539     ZEND_ARG_INFO(0, start)
540     ZEND_ARG_INFO(0, stop)
541 ZEND_END_ARG_INFO()
542 
543 ZEND_BEGIN_ARG_INFO_EX(arginfo_publish, 0, 0, 2)
544     ZEND_ARG_INFO(0, channel)
545     ZEND_ARG_INFO(0, message)
546 ZEND_END_ARG_INFO()
547 
548 ZEND_BEGIN_ARG_INFO_EX(arginfo_pfadd, 0, 0, 2)
549     ZEND_ARG_INFO(0, key)
550     ZEND_ARG_ARRAY_INFO(0, elements, 0)
551 ZEND_END_ARG_INFO()
552 
553 ZEND_BEGIN_ARG_INFO_EX(arginfo_pfmerge, 0, 0, 2)
554     ZEND_ARG_INFO(0, dstkey)
555     ZEND_ARG_ARRAY_INFO(0, keys, 0)
556 ZEND_END_ARG_INFO()
557 
558 ZEND_BEGIN_ARG_INFO_EX(arginfo_restore, 0, 0, 3)
559     ZEND_ARG_INFO(0, ttl)
560     ZEND_ARG_INFO(0, key)
561     ZEND_ARG_INFO(0, value)
562 ZEND_END_ARG_INFO()
563 
564 ZEND_BEGIN_ARG_INFO_EX(arginfo_smove, 0, 0, 3)
565     ZEND_ARG_INFO(0, src)
566     ZEND_ARG_INFO(0, dst)
567     ZEND_ARG_INFO(0, value)
568 ZEND_END_ARG_INFO()
569 
570 ZEND_BEGIN_ARG_INFO_EX(arginfo_zrange, 0, 0, 3)
571     ZEND_ARG_INFO(0, key)
572     ZEND_ARG_INFO(0, start)
573     ZEND_ARG_INFO(0, end)
574     ZEND_ARG_INFO(0, scores)
575 ZEND_END_ARG_INFO()
576 
577 ZEND_BEGIN_ARG_INFO_EX(arginfo_zrangebyscore, 0, 0, 3)
578     ZEND_ARG_INFO(0, key)
579     ZEND_ARG_INFO(0, start)
580     ZEND_ARG_INFO(0, end)
581     ZEND_ARG_ARRAY_INFO(0, options, 0)
582 ZEND_END_ARG_INFO()
583 
584 ZEND_BEGIN_ARG_INFO_EX(arginfo_zrangebylex, 0, 0, 3)
585     ZEND_ARG_INFO(0, key)
586     ZEND_ARG_INFO(0, min)
587     ZEND_ARG_INFO(0, max)
588     ZEND_ARG_INFO(0, offset)
589     ZEND_ARG_INFO(0, limit)
590 ZEND_END_ARG_INFO()
591 
592 ZEND_BEGIN_ARG_INFO_EX(arginfo_zstore, 0, 0, 2)
593     ZEND_ARG_INFO(0, key)
594     ZEND_ARG_ARRAY_INFO(0, keys, 0)
595     ZEND_ARG_ARRAY_INFO(0, weights, 1)
596     ZEND_ARG_INFO(0, aggregate)
597 ZEND_END_ARG_INFO()
598 
599 ZEND_BEGIN_ARG_INFO_EX(arginfo_sort, 0, 0, 1)
600     ZEND_ARG_INFO(0, key)
601     ZEND_ARG_ARRAY_INFO(0, options, 0)
602 ZEND_END_ARG_INFO()
603 
604 ZEND_BEGIN_ARG_INFO_EX(arginfo_object, 0, 0, 2)
605     ZEND_ARG_INFO(0, field)
606     ZEND_ARG_INFO(0, key)
607 ZEND_END_ARG_INFO()
608 
609 ZEND_BEGIN_ARG_INFO_EX(arginfo_subscribe, 0, 0, 2)
610     ZEND_ARG_ARRAY_INFO(0, channels, 0)
611     ZEND_ARG_INFO(0, callback)
612 ZEND_END_ARG_INFO()
613 
614 ZEND_BEGIN_ARG_INFO_EX(arginfo_psubscribe, 0, 0, 2)
615     ZEND_ARG_ARRAY_INFO(0, patterns, 0)
616     ZEND_ARG_INFO(0, callback)
617 ZEND_END_ARG_INFO()
618 
619 ZEND_BEGIN_ARG_INFO_EX(arginfo_unsubscribe, 0, 0, 1)
620     ZEND_ARG_INFO(0, channel)
621     ZEND_ARG_VARIADIC_INFO(0, other_channels)
622 ZEND_END_ARG_INFO()
623 
624 ZEND_BEGIN_ARG_INFO_EX(arginfo_punsubscribe, 0, 0, 1)
625     ZEND_ARG_INFO(0, pattern)
626     ZEND_ARG_VARIADIC_INFO(0, other_patterns)
627 ZEND_END_ARG_INFO()
628 
629 ZEND_BEGIN_ARG_INFO_EX(arginfo_eval, 0, 0, 1)
630     ZEND_ARG_INFO(0, script)
631     ZEND_ARG_INFO(0, args)
632     ZEND_ARG_INFO(0, num_keys)
633 ZEND_END_ARG_INFO()
634 
635 ZEND_BEGIN_ARG_INFO_EX(arginfo_evalsha, 0, 0, 1)
636     ZEND_ARG_INFO(0, script_sha)
637     ZEND_ARG_INFO(0, args)
638     ZEND_ARG_INFO(0, num_keys)
639 ZEND_END_ARG_INFO()
640 
641 ZEND_BEGIN_ARG_INFO_EX(arginfo_getoption, 0, 0, 1)
642     ZEND_ARG_INFO(0, option)
643 ZEND_END_ARG_INFO()
644 
645 ZEND_BEGIN_ARG_INFO_EX(arginfo_setoption, 0, 0, 2)
646     ZEND_ARG_INFO(0, option)
647     ZEND_ARG_INFO(0, value)
648 ZEND_END_ARG_INFO()
649 
650 ZEND_BEGIN_ARG_INFO_EX(arginfo_watch, 0, 0, 1)
651     ZEND_ARG_INFO(0, key)
652     ZEND_ARG_VARIADIC_INFO(0, other_keys)
653 ZEND_END_ARG_INFO()
654 
655 ZEND_BEGIN_ARG_INFO_EX(arginfo_command, 0, 0, 0)
656     ZEND_ARG_VARIADIC_INFO(0, args)
657 ZEND_END_ARG_INFO()
658 
659 ZEND_BEGIN_ARG_INFO_EX(arginfo_rawcommand, 0, 0, 1)
660     ZEND_ARG_INFO(0, cmd)
661     ZEND_ARG_VARIADIC_INFO(0, args)
662 ZEND_END_ARG_INFO()
663 
664 ZEND_BEGIN_ARG_INFO_EX(arginfo_geoadd, 0, 0, 4)
665     ZEND_ARG_INFO(0, key)
666     ZEND_ARG_INFO(0, lng)
667     ZEND_ARG_INFO(0, lat)
668     ZEND_ARG_INFO(0, member)
669     ZEND_ARG_VARIADIC_INFO(0, other_triples)
670 ZEND_END_ARG_INFO()
671 
672 ZEND_BEGIN_ARG_INFO_EX(arginfo_geodist, 0, 0, 3)
673     ZEND_ARG_INFO(0, key)
674     ZEND_ARG_INFO(0, src)
675     ZEND_ARG_INFO(0, dst)
676     ZEND_ARG_INFO(0, unit)
677 ZEND_END_ARG_INFO()
678 
679 ZEND_BEGIN_ARG_INFO_EX(arginfo_georadius, 0, 0, 5)
680     ZEND_ARG_INFO(0, key)
681     ZEND_ARG_INFO(0, lng)
682     ZEND_ARG_INFO(0, lan)
683     ZEND_ARG_INFO(0, radius)
684     ZEND_ARG_INFO(0, unit)
685     ZEND_ARG_ARRAY_INFO(0, opts, 0)
686 ZEND_END_ARG_INFO()
687 
688 ZEND_BEGIN_ARG_INFO_EX(arginfo_georadiusbymember, 0, 0, 4)
689     ZEND_ARG_INFO(0, key)
690     ZEND_ARG_INFO(0, member)
691     ZEND_ARG_INFO(0, radius)
692     ZEND_ARG_INFO(0, unit)
693     ZEND_ARG_ARRAY_INFO(0, opts, 0)
694 ZEND_END_ARG_INFO()
695 
696 ZEND_BEGIN_ARG_INFO_EX(arginfo_xadd, 0, 0, 3)
697     ZEND_ARG_INFO(0, str_key)
698     ZEND_ARG_INFO(0, str_id)
699     ZEND_ARG_ARRAY_INFO(0, arr_fields, 0)
700     ZEND_ARG_INFO(0, i_maxlen)
701     ZEND_ARG_INFO(0, boo_approximate)
702 ZEND_END_ARG_INFO()
703 
704 ZEND_BEGIN_ARG_INFO_EX(arginfo_xpending, 0, 0, 2)
705     ZEND_ARG_INFO(0, str_key)
706     ZEND_ARG_INFO(0, str_group)
707     ZEND_ARG_INFO(0, str_start)
708     ZEND_ARG_INFO(0, str_end)
709     ZEND_ARG_INFO(0, i_count)
710     ZEND_ARG_INFO(0, str_consumer)
711 ZEND_END_ARG_INFO()
712 
713 ZEND_BEGIN_ARG_INFO_EX(arginfo_xrange, 0, 0, 3)
714     ZEND_ARG_INFO(0, str_key)
715     ZEND_ARG_INFO(0, str_start)
716     ZEND_ARG_INFO(0, str_end)
717     ZEND_ARG_INFO(0, i_count)
718 ZEND_END_ARG_INFO()
719 
720 ZEND_BEGIN_ARG_INFO_EX(arginfo_xread, 0, 0, 1)
721     ZEND_ARG_ARRAY_INFO(0, arr_streams, 0)
722     ZEND_ARG_INFO(0, i_count)
723     ZEND_ARG_INFO(0, i_block)
724 ZEND_END_ARG_INFO()
725 
726 ZEND_BEGIN_ARG_INFO_EX(arginfo_xreadgroup, 0, 0, 3)
727     ZEND_ARG_INFO(0, str_group)
728     ZEND_ARG_INFO(0, str_consumer)
729     ZEND_ARG_ARRAY_INFO(0, arr_streams, 0)
730     ZEND_ARG_INFO(0, i_count)
731     ZEND_ARG_INFO(0, i_block)
732 ZEND_END_ARG_INFO()
733 
734 ZEND_BEGIN_ARG_INFO_EX(arginfo_xack, 0, 0, 3)
735     ZEND_ARG_INFO(0, str_key)
736     ZEND_ARG_INFO(0, str_group)
737     ZEND_ARG_ARRAY_INFO(0, arr_ids, 0)
738 ZEND_END_ARG_INFO()
739 
740 ZEND_BEGIN_ARG_INFO_EX(arginfo_xclaim, 0, 0, 5)
741     ZEND_ARG_INFO(0, str_key)
742     ZEND_ARG_INFO(0, str_group)
743     ZEND_ARG_INFO(0, str_consumer)
744     ZEND_ARG_INFO(0, i_min_idle)
745     ZEND_ARG_ARRAY_INFO(0, arr_ids, 0)
746     ZEND_ARG_ARRAY_INFO(0, arr_opts, 0)
747 ZEND_END_ARG_INFO()
748 
749 ZEND_BEGIN_ARG_INFO_EX(arginfo_xgroup, 0, 0, 1)
750     ZEND_ARG_INFO(0, str_operation)
751     ZEND_ARG_INFO(0, str_key)
752     ZEND_ARG_INFO(0, str_arg1)
753     ZEND_ARG_INFO(0, str_arg2)
754     ZEND_ARG_INFO(0, str_arg3)
755 ZEND_END_ARG_INFO()
756 
757 ZEND_BEGIN_ARG_INFO_EX(arginfo_xinfo, 0, 0, 1)
758     ZEND_ARG_INFO(0, str_cmd)
759     ZEND_ARG_INFO(0, str_key)
760     ZEND_ARG_INFO(0, str_group)
761 ZEND_END_ARG_INFO()
762 
763 ZEND_BEGIN_ARG_INFO_EX(arginfo_xtrim, 0, 0, 2)
764     ZEND_ARG_INFO(0, str_key)
765     ZEND_ARG_INFO(0, i_maxlen)
766     ZEND_ARG_INFO(0, boo_approximate)
767 ZEND_END_ARG_INFO()
768 
769 ZEND_BEGIN_ARG_INFO_EX(arginfo_xdel, 0, 0, 2)
770     ZEND_ARG_INFO(0, str_key)
771     ZEND_ARG_ARRAY_INFO(0, arr_ids, 0)
772 ZEND_END_ARG_INFO()
773 
774 #endif
775