|
32 | 32 |
|
33 | 33 | #include <zend_exceptions.h> |
34 | 34 |
|
| 35 | +/* Config operations */ |
| 36 | +typedef enum redisConfigOp { |
| 37 | + REDIS_CFG_RESETSTAT, |
| 38 | + REDIS_CFG_REWRITE, |
| 39 | + REDIS_CFG_GET, |
| 40 | + REDIS_CFG_SET, |
| 41 | +} redisConfigOp; |
| 42 | + |
35 | 43 | /* Georadius sort type */ |
36 | 44 | typedef enum geoSortType { |
37 | 45 | SORT_NONE, |
@@ -728,6 +736,148 @@ int redis_zrangebyscore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, |
728 | 736 | return SUCCESS; |
729 | 737 | } |
730 | 738 |
|
| 739 | +static int redis_get_config_op(enum redisConfigOp *dst, zend_string *op) { |
| 740 | + if (zend_string_equals_literal_ci(op, "RESETSTAT")) |
| 741 | + *dst = REDIS_CFG_RESETSTAT; |
| 742 | + else if (zend_string_equals_literal_ci(op, "REWRITE")) |
| 743 | + *dst = REDIS_CFG_REWRITE; |
| 744 | + else if (zend_string_equals_literal_ci(op, "GET")) |
| 745 | + *dst = REDIS_CFG_GET; |
| 746 | + else if (zend_string_equals_literal_ci(op, "SET")) |
| 747 | + *dst = REDIS_CFG_SET; |
| 748 | + else |
| 749 | + return FAILURE; |
| 750 | + |
| 751 | + return SUCCESS; |
| 752 | +} |
| 753 | + |
| 754 | +static int redis_build_config_get_cmd(smart_string *dst, zval *val) { |
| 755 | + zend_string *zstr; |
| 756 | + int ncfg; |
| 757 | + zval *zv; |
| 758 | + |
| 759 | + if (val == NULL || (Z_TYPE_P(val) != IS_STRING && Z_TYPE_P(val) != IS_ARRAY)) { |
| 760 | + php_error_docref(NULL, E_WARNING, "Must pass a string or array of values to CONFIG GET"); |
| 761 | + return FAILURE; |
| 762 | + } else if (Z_TYPE_P(val) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(val)) == 0) { |
| 763 | + php_error_docref(NULL, E_WARNING, "Cannot pass an empty array to CONFIG GET"); |
| 764 | + return FAILURE; |
| 765 | + } |
| 766 | + |
| 767 | + ncfg = Z_TYPE_P(val) == IS_STRING ? 1 : zend_hash_num_elements(Z_ARRVAL_P(val)); |
| 768 | + |
| 769 | + REDIS_CMD_INIT_SSTR_STATIC(dst, 1 + ncfg, "CONFIG"); |
| 770 | + REDIS_CMD_APPEND_SSTR_STATIC(dst, "GET"); |
| 771 | + |
| 772 | + if (Z_TYPE_P(val) == IS_STRING) { |
| 773 | + redis_cmd_append_sstr_zstr(dst, Z_STR_P(val)); |
| 774 | + } else { |
| 775 | + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(val), zv) { |
| 776 | + ZVAL_DEREF(zv); |
| 777 | + |
| 778 | + zstr = zval_get_string(zv); |
| 779 | + redis_cmd_append_sstr_zstr(dst, zstr); |
| 780 | + zend_string_release(zstr); |
| 781 | + } ZEND_HASH_FOREACH_END(); |
| 782 | + } |
| 783 | + |
| 784 | + return SUCCESS; |
| 785 | +} |
| 786 | + |
| 787 | +static int redis_build_config_set_cmd(smart_string *dst, zval *key, zend_string *val) { |
| 788 | + zend_string *zkey, *zstr; |
| 789 | + zval *zv; |
| 790 | + |
| 791 | + /* Legacy case: CONFIG SET <string> <string> */ |
| 792 | + if (key != NULL && val != NULL) { |
| 793 | + REDIS_CMD_INIT_SSTR_STATIC(dst, 3, "CONFIG"); |
| 794 | + REDIS_CMD_APPEND_SSTR_STATIC(dst, "SET"); |
| 795 | + |
| 796 | + zstr = zval_get_string(key); |
| 797 | + redis_cmd_append_sstr_zstr(dst, zstr); |
| 798 | + zend_string_release(zstr); |
| 799 | + |
| 800 | + redis_cmd_append_sstr_zstr(dst, val); |
| 801 | + |
| 802 | + return SUCCESS; |
| 803 | + } |
| 804 | + |
| 805 | + /* Now we must have an array with at least one element */ |
| 806 | + if (key == NULL || Z_TYPE_P(key) != IS_ARRAY || zend_hash_num_elements(Z_ARRVAL_P(key)) == 0) { |
| 807 | + php_error_docref(NULL, E_WARNING, "Must either pass two strings to CONFIG SET or a non-empty array of values"); |
| 808 | + return FAILURE; |
| 809 | + } |
| 810 | + |
| 811 | + REDIS_CMD_INIT_SSTR_STATIC(dst, 1 + (2 * zend_hash_num_elements(Z_ARRVAL_P(key))), "CONFIG"); |
| 812 | + REDIS_CMD_APPEND_SSTR_STATIC(dst, "SET"); |
| 813 | + |
| 814 | + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(key), zkey, zv) { |
| 815 | + if (zkey == NULL) |
| 816 | + goto fail; |
| 817 | + |
| 818 | + ZVAL_DEREF(zv); |
| 819 | + |
| 820 | + redis_cmd_append_sstr_zstr(dst, zkey); |
| 821 | + |
| 822 | + zstr = zval_get_string(zv); |
| 823 | + redis_cmd_append_sstr_zstr(dst, zstr); |
| 824 | + zend_string_release(zstr); |
| 825 | + } ZEND_HASH_FOREACH_END(); |
| 826 | + |
| 827 | + return SUCCESS; |
| 828 | + |
| 829 | +fail: |
| 830 | + php_error_docref(NULL, E_WARNING, "Must pass an associate array of config keys and values"); |
| 831 | + efree(dst->c); |
| 832 | + memset(dst, 0, sizeof(*dst)); |
| 833 | + return FAILURE; |
| 834 | +} |
| 835 | + |
| 836 | +int |
| 837 | +redis_config_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, |
| 838 | + char **cmd, int *cmd_len, short *slot, void **ctx) |
| 839 | +{ |
| 840 | + zend_string *op = NULL, *arg = NULL; |
| 841 | + smart_string cmdstr = {0}; |
| 842 | + enum redisConfigOp cfg_op; |
| 843 | + int res = FAILURE; |
| 844 | + zval *key = NULL; |
| 845 | + |
| 846 | + ZEND_PARSE_PARAMETERS_START(1, 3) |
| 847 | + Z_PARAM_STR(op) |
| 848 | + Z_PARAM_OPTIONAL |
| 849 | + Z_PARAM_ZVAL_OR_NULL(key) |
| 850 | + Z_PARAM_STR_OR_NULL(arg) |
| 851 | + ZEND_PARSE_PARAMETERS_END_EX(return FAILURE); |
| 852 | + |
| 853 | + if (redis_get_config_op(&cfg_op, op) != SUCCESS) { |
| 854 | + php_error_docref(NULL, E_WARNING, "Unknown operation '%s'", ZSTR_VAL(op)); |
| 855 | + return FAILURE; |
| 856 | + } |
| 857 | + |
| 858 | + switch (cfg_op) { |
| 859 | + case REDIS_CFG_RESETSTAT: /* fallthrough */ |
| 860 | + case REDIS_CFG_REWRITE: |
| 861 | + REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 1, "CONFIG"); |
| 862 | + redis_cmd_append_sstr_zstr(&cmdstr, op); |
| 863 | + *ctx = redis_boolean_response; |
| 864 | + res = SUCCESS; |
| 865 | + break; |
| 866 | + case REDIS_CFG_GET: |
| 867 | + res = redis_build_config_get_cmd(&cmdstr, key); |
| 868 | + *ctx = redis_mbulk_reply_zipped_raw; |
| 869 | + break; |
| 870 | + case REDIS_CFG_SET: |
| 871 | + res = redis_build_config_set_cmd(&cmdstr, key, arg); |
| 872 | + *ctx = redis_boolean_response; |
| 873 | + break; |
| 874 | + } |
| 875 | + |
| 876 | + *cmd = cmdstr.c; |
| 877 | + *cmd_len = cmdstr.len; |
| 878 | + return res; |
| 879 | +} |
| 880 | + |
731 | 881 | int |
732 | 882 | redis_zrandmember_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, |
733 | 883 | char **cmd, int *cmd_len, short *slot, void **ctx) |
|
0 commit comments