140 Commits

Author SHA1 Message Date
michael-grunder 2c5ef19257 Introduce new RedisCmd based command construction
* Introduce a new `RedisCmd` struct to dynamically append RESP arguments
  such that we don't have to precalculate the number of arguments the
  command will have up front.

  Additionally the new `RedisCmd allows both a `void *` context pointer
  but also can attach a `void (*ctx_dtor)(void*)` destructor so we are
  still able to clean up any allocated context when commands fail.

  This moves the context cleanup out of every individual reply handler
  and into the generic processing wrappers.

* Create a small group of `resp_str` helper functions for lower level
  concatination of RESP protocol data over the wire.

* Lots of small modernization of the codebase such as using
  `zend_string*` instead of (`char *`, `size_t`) pairs.

* Greatly simplify `crosslot` handling logic
2026-06-04 12:16:35 -07:00
michael-grunder 10b77a42d6 Implement GCRA command 2026-03-25 11:03:42 -07:00
michael-grunder 635d87d535 Implement XDELEX command 2025-11-12 09:14:43 -08:00
michael-grunder 86eabb86eb Implement MSETEX and refactor SET.
* Implement the new `MSETEX` Redis command.
* Refactor parsing of extended `SET` arguments into unified helper
  functions, deduplicating logic.
* Add new `SET` arguments `IFNE`, `IFDEQ`, and `IFDNE`. We already
  support Valkey's existing `IFEQ` argument, which Redis has added.

Fixes #2742
2025-11-12 08:41:21 -08:00
michael-grunder 00c62de277 Implement DELEX command 2025-11-06 09:48:09 -08:00
michael-grunder e2dd13ce7b Implement DIGEST and _digest helper (for php >= 8.1)
Redis implemented new CAS semantics which work both with values and the
XXH3 digest of those values.

This commit implements the Redis command itself and a helper which
computes the XXH3 digest locally. Note that we can only be sure to have
the `XXH3` hashing algorithm in PHP >= 8.1 so the `_digest` helper is
limited to PHP 8.1 or newer.
2025-11-06 09:48:09 -08:00
michael-grunder 6ce3bd533a Implement VRANGE command and add a test 2025-10-02 11:12:39 -07:00
michael-grunder d80b725824 Implement VGETATTR command 2025-09-01 09:41:12 -07:00
michael-grunder 7f9b1f416e Implement VLINKS command 2025-09-01 09:41:12 -07:00
michael-grunder 92716ed0c5 Implement VSETATTR command 2025-09-01 09:41:12 -07:00
michael-grunder 65927b53b1 We can use redis_kv_cmd instead of a specific vrem command. 2025-09-01 09:41:12 -07:00
michael-grunder dc91631b3f Implement VREM command
See #2543
2025-09-01 09:41:12 -07:00
michael-grunder 1deca62841 Implement VRANDMEMBER
`VRANDMEMBER` has the exact same semantics of `SRANDMEMBER` so make
`SRANDMEMBER` a keyword based command and use it for `VRANDMEMBER`.

See #2543
2025-09-01 09:41:12 -07:00
michael-grunder 96378b70fd Implement VEMB and slightly rework VINFO
Unfortunately `VEMB` has a unique `RESP2` reply as far as I can tell,
where it sends the embedding mode (int8, bin, fp32) as a simple string.

This would cause any of PhpRedis' generic reply handlers to turn that
into `true` which isn't useful. For that reason we need a custom reply
handler.

Additionally slightly rework `VINFO` to short circuit and return failure
if we read anything other than a bulk string or an integer reply type.
Otherwise we may get out of sync on the socket.

See #2543
2025-09-01 09:41:12 -07:00
michael-grunder 950d2bc79d Rework REDIS_PROCESS_KW_CMD as a function 2025-08-21 08:53:51 -07:00
michael-grunder b90e27f285 Rework CLUSTER_PROCESS_KW_CMD to be a small wrapper macro + function
This commit is similar to the last one reworking processing keyword
commands to work to use a function instead of a big multiline macro.
2025-08-21 08:53:51 -07:00
michael-grunder 1db3908914 Rework CLUSTER_PROCESS_CMD to use an underlying function
In theory this should reduce PhpRedis' code size and likely doesn't
affect performance in a measurable way.
2025-08-21 08:53:51 -07:00
michael-grunder d1d690053f Implement VSIM command
This command is similar to `VADD` in that it's pretty simple but allows
for a great many options.

In it's most basic form:

```php
// To get similarity of a different element
$redis->vsim('myvec', 'some-element');

// To get similarity for a vector of scores
```

As seen above the method attempts to infer element or vector from the
argument passed to $member`. However, since we do serialize the member
when doing `ELE` mode, the user can also specify `ELE` explicitly in the
options array to force an `ELE` search sending serialized values.

```php
$redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP);
$redis->vsim('myvec', [3.14, 2.71], ['ELE']);
```

See #2543
2025-07-31 08:30:47 -07:00
michael-grunder 286fa63064 Implement VADD command
This is for Redis 8.0's vector sets.

The command itself can be quite complex with all of the various options but
pretty simple using all defaults.

```php
$redis->vadd('myvec', [3.14, 2.17], 'myelement');
```

The implementation takes a default argument `$options` which can be an array in
order to specify the myriad of other knobs users can send. We just do a bit of
validation on inputs (e.g. certain numeric options must be positive) and make
sure the command is constructed in a valid way (e.g. REDUCE <dim> must come
before the floating point values).

By default we deliver `FP32` blobs but allow the user to send `VALUES` in the
options array which will cause PhpRedis to send N individual values. Sending
values is slower but might be nice for debugging (e.g. watching monitor)

See #2543
2025-07-31 00:57:28 -07:00
Michael Grunder ce5b0facc2 Implement HGETEX, HSETEX, HGETDEL, and refactor HMGET (#2667)
* Rework HMGET and implement HGETEX

Instead of using a bespoke NULL terminated `zval**` array for the
context array we can use a `HashTable`. This might be a tiny bit more
expensive but Zend hashtables are quite efficient and this should also
be less error prone.

* Rework our `HashTable` context array to store keys

Instead of sending an array of values we can instead add the fields as
keys to our context array. That way when we combine the keys with the
Redis provided values we can do it in-place and then just give the
HashTable to the user to then do with what they want.

* Implement HGETDEL command.

* Fix edge cases to abide by legacy behavior.

Previously we coerced integer strings into integer keys when zipping
`HMGET` responses. This commit adds logic so we continue to do this and
do not change semantics.

* Implement `HGETDEL` and `HGETEX` for `RedisCluster`.

This commit implements the new commands and reworks the `HMGET` reply
handler to use the new context `HashTable`.

* Fix an edge case where we get zero multiblk elements

* Tests for `HGETEX` and `HGETDEL`

* Minor logic improvement

We don't need to check if `c->reply_len > 0` in the last else block
since we have already determined it must be.

* Implement `HSETEX` for `Redis` and `RedisCluster`

* Use `zval_get_tmp_string` ro populating non-long keys
2025-07-16 16:46:09 -07:00
michael-grunder 7350768cd9 Implement several hash expiration commands
Commands implemented:

`H[P]EXPIRE`
`H[P]TTL`
`H[P]EXPIREAT`
`H[P]EXPIRETIME`
`HPERSIST`
2025-05-07 08:16:14 -07:00
Bentley O'Kane-Chase 138d07b67c Print cursor as unsigned 64 bit integer 2024-12-17 17:08:36 -08:00
michael-grunder 4cd3f59356 Implement KeyDB's EXPIREMEMBER[AT] commands 2024-11-15 08:59:10 -08:00
michael-grunder ed7c9f6f63 Implement WAITAOF command. 2024-02-14 12:03:29 -08:00
Pavlo Yatsukhnenko 7c46ad2c05 Issue #2068
Add FCALL/FCALL_RO commands
2022-12-24 13:37:50 +02:00
Pavlo Yatsukhnenko 90a0e9cc0e Add Redis::function command 2022-12-18 18:21:42 +02:00
michael-grunder 6d10448109 Refactor MSET and MSETNX commands.
Switch to using our normal command handling logic for MSET and MSETNX.
2022-12-10 11:57:24 -08:00
michael-grunder 3574ef0867 Refactor INFO and SCRIPT commands.
Use `gen_varkey_cmd` for INFO and SCRIPT.
2022-12-10 11:45:08 -08:00
michael-grunder 8cb6dd17fe Refactor MGET command. 2022-12-07 11:18:25 -08:00
michael-grunder acb5db7661 Refactor OBJECT command. 2022-12-06 12:42:29 -08:00
michael-grunder f62363c2a3 Refactor SRANDMEMBER command. 2022-12-06 10:46:32 -08:00
michael-grunder 86f15ccaa1 Refactor SELECT command.
* Use our common command handler logic for SELECT.

* Shift updating `redis_sock->dbNumber` from the command itself to the
  reply handler, so we aren't erroneously pointing to a non-existent
  database before the command succeeds.
2022-12-06 10:46:17 -08:00
michael-grunder 79c9d2241f Refactor rawCommand and WAIT 2022-12-03 23:32:24 -08:00
michael-grunder 121e9d9c29 Implement BLMOVE and add LMOVE/BLMOVE to cluster.
* Refactor `redis_lmove_cmd` to work for both `LMOVE` and `BLMOVE`
* Implement `LMOVE` and `BLMOVE` in RedisCluster.

See #1894
2022-12-01 13:48:03 -08:00
Pavlo Yatsukhnenko 504810a5d1 Issue #2068, Refactor ACL command 2022-11-01 12:53:23 +02:00
michael-grunder f2cef8be06 More docblocks and refactor SLAVEOF command.
Add additional complete docblocks for a few more commands.

Refactor SLAVEOF handler to conform with more modern PhpRedis command
handlers.

Create REPLICAOF and deprecate SLAVEOF as Redis has done since 5.0.0.
2022-10-31 22:32:43 -07:00
Pavlo Yatsukhnenko 2a0d1c1e6d Refactor PubSub command 2022-10-31 17:01:35 -07:00
Pavlo Yatsukhnenko 2bb6403883 Issue #1894
Add the CH, NX, XX arguments to GEOADD
2022-10-30 12:00:12 -07:00
michael-grunder dc1f2398d0 TOUCH command
Implement the TOUCH command and refactor several of our "variadic key"
commands, which were previously all using their own specific handlers.

While refactoring the code, I changed `EXISTS` to require one key (it
had previously been set to require zero keys).

Additonally, it looks like we had a disparity in two commands which
should be idential to PhpRedis:  SINTERSTORE and SUNIONSTORE.
Previously, SINTERSTORE required only one argument but SUNIONSTORE 2.

I simply changed SUNIONSTORE to also only require a single argument,
since that argument could be an array.

```php
$redis->sInterStore(['dst', 'src1', 'src2']);
$redis->sUnionStore(['dst', 'src1', 'src2']);
```
2022-10-26 01:38:42 -07:00
michael-grunder 8c7c5a3aa2 Refactor SORT and add SORT_RO command
See #2068
2022-10-23 13:18:13 -07:00
michael-grunder 71bcbcb973 Implement ZRANGESTORE and add ZRANGE options
* Add ZRANGESTORE command.

* Add Redis 6.2's `REV`, `BYLEX`, and `BYSCORE` to ZRANGE options.

* Refactor several ZRANGE family commands into a single reply and
  options handler, using PHP's new argument parsing macros.

* Extend our tests to use the new ZRANGE options.

See #1894
2022-10-22 12:46:01 -07:00
michael-grunder d87f142826 Refactor SLOWLOG command
Refactor the slowlog command to use the new argument parsing API and
also change it so we no longer manually handle atomic/non-atomic
logic in the handler itself.
2022-10-19 12:58:39 -07:00
michael-grunder 36ef4bd8d1 Variadic CONFIG GET/SET
Redis 7.0.0 allows for getting and setting multiple config values as an
atomic operation.  In order to support this while maintaining backward
compatibility, the CONFIG command is reworked to also accept an array of
values or keys and values.

See: #2068
2022-10-19 09:15:16 -07:00
michael-grunder 872ae1079f Implement Redis 7.0.0 [P]EXPIRE[AT] options
See #2068
2022-10-13 11:31:28 -07:00
michael-grunder 9a3fe401dc Implement new RESTORE options
Add the new RESTORE options REPLACE, ABSTTL, FREQ <freq> and IDLETIME <idletime>

Fixes #1410
2022-10-08 10:51:50 -07:00
michael-grunder 6ea978eb72 [B]LMPOP and [B]ZMPOP commands
Implement the new Redis 7.0.0 commands to pop multiple elements from one
or more lists/zsets.

Additionally, remove INTERNAL_FUNCTION_PARAMETERS from the
redis_sock_read_multibulk_reply_zval helper function as it wasn't
actually being used.
2022-10-08 09:23:13 -07:00
michael-grunder c0e839f6ac LCS command
Implement the Redis 7.0.0 LCS command with tests.
2022-10-01 10:42:23 -07:00
michael-grunder 6430050808 SINTERCARD and ZINTERCARD commands
Implement Redis 7.0.0 commands SINTERCARD and ZINTERCARD.
2022-10-01 10:42:23 -07:00
Pavlo Yatsukhnenko a8d10291a2 Redis::client command 2022-09-07 22:47:02 +03:00
Pavlo Yatsukhnenko 687a5c7880 Issue #1943
Add lPos command.
2022-08-03 22:28:08 +03:00