193 Commits

Author SHA1 Message Date
michael-grunder ea3ea564d0 Fix: Harden PhpRedis against protocol errors
* Fix a double free when zipping keys and scores.
* Instead of aborting with an assertion if elements != 2 just warn and
  return failure
* Instead of crashing on `xclaim` reply shape issues, just return false
2026-06-15 14:13:16 -07:00
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 7b2fdc6de1 fix: Guard against bulk length overflow
Clamp range in a couple library functions to values that can fit into an
iint, since we narrow it later.

A more comprehensive change that widens all of these values to 64 bits
will come in a future commit.
2026-06-01 11:48:09 -07:00
Ilia Alshanetsky c67d3e493f library: redis_sock_getc returns int not char to detect EOF
php_stream_getc returns int; storing into a char truncates the EOF
sentinel. On unsigned-char platforms (ARM Linux, AIX, PPC) EOF == -1
becomes 0xFF after promotion and res != EOF is always true; on
signed-char platforms a server byte of 0xFF is indistinguishable
from real EOF. Subscribe loops can busy-loop or stall. Return int,
matching the standard getc-style convention.
2026-05-19 21:07:47 -07:00
michael-grunder e39d9b74f4 Modernize session locking
Add support for Redis' `DELEX` and Valkey's `DELIFEQ` when deleting the
session lock key. Local testing shows about a 10-15% improvement over
the current `EVAL[SHA]` strategy.

This commit adds a new INI settingg:
```ini
redis.session.lock_release_cmd = delex|delifeq|eval
```

By default we continue to use the `EVAL` logic and if a user specifies
another mechanism but the command doesn't exist, we warn the user and
fall back to EVAL.

This commit also refactors a few functions to avoid UB and simplify key
construction.
2026-03-01 14:52:39 -08:00
michael-grunder b97951cddc Rework TLS context logic
Instead of currying around a `php_stream_context` object, just retain
the context array provided by the user itself like we do with other
connection information like host and port. This lets users reconnect in
a loop without leaking memory.

```php
$redis = new \Redis;
while (true) {
    // Previously each reconnect call would leak the
    // `php_stream_context` structure.
    $redis->connect('tls://127.0.0.1', 9999, 1, null, 0, 0, [
        'stream' => ['verify_peer' => false, 'verify_peer_name' => false],
    ]);

    $redis->ping();

    $redis->close();
}
```
2026-02-18 09:46:55 -08:00
michael-grunder 35df8ad7c2 Attempt to fix an overflow bug in ZADD on Windows
Theory: In 64 bit windows `long` is 32 bits wide meaning that using a
long to append `ZADD` scores can truncate.

Possible fix for #2697
2025-09-09 16:30:43 -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 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 0fda9f293b Implement VCARD, VDIM, and VINFO
All of these commands have the same form `<cmd> key`. `VINFO` is a bit
of an outlier however that uses simple strings as opposed to bulk
strings for the key names, meaning we had to create a custom handler.

See #2543
2025-09-01 09:41:12 -07:00
Michael Grunder 0445e683e7 Refactor getWithMeta logic (#2643)
* Refactor `getWithMeta`

* Consolidate `getWithMeta()` test.

* Review comments
2025-03-31 12:42:29 -07:00
Pavlo Yatsukhnenko 056c2dbee7 Introduce Redis::serverName and Redis::serverVersion methods
Right now we can't implement `HELLO` command to switch protocol
because we don't support new reply types that come with RESP3.
But we can use `HELLO` reply to expose some server information.
2025-03-20 10:38:56 -07:00
Pavlo Yatsukhnenko 9036ffca6a Add getWithMeta method 2025-02-25 16:27:10 +02:00
Bentley O'Kane-Chase 35c5988027 Formatting improvements 2024-12-17 17:08:36 -08:00
Bentley O'Kane-Chase 138d07b67c Print cursor as unsigned 64 bit integer 2024-12-17 17:08:36 -08:00
Jakub Onderka a551fdc94c Switch from linked list to growing array for reply callbacks
Reduce allocation and deallocation count and also memory usage when using pipelining
2024-12-09 10:40:39 -08:00
Jakub Onderka 64da891e6f Do not allocate empty string or string with one character
From PHP 8, empty strings or string with one character don't need to be allocated. This change will reduce memory usage.
2024-11-26 10:39:23 -08:00
michael-grunder 2612d444e5 Update RedisCluster scan logic for large SCAN cursors.
We also need to update the `RedisCluster` logic to handle very large
curosr values, in addition to handling them for the `Redis` and
`RedisArray` classes.

See #2454, #2458
2024-03-18 11:54:02 -07:00
michael-grunder e52f0afaed Update SCAN to handle very large cursor values.
Technically Redis may return any unsigned 64 bit integer as a scan
cursor.  This presents a problem for PHP in that PHP's integers are
signed.  Because of that if a scan cursor is > 2^63 it will overflow and
fail to work properly.

This commit updates our SCAN family of commands to deliver cursors in
their string form.

```php
public function scan(null|int|string $iterator, ...);
```

On initial entry into our SCAN family we convert either a NULL or empty
string cursor to zero, and send the initial scan command.

As Redis replies with cursors we either represent them as a long (if
they are <= ZEND_ULONG_MAX) and as a string if greater.  This should
mean the fix is minimally breaking as the following code will still
work:

```php
$it = NULL;
do {
    print_r($redis->scan($it));
} while ($it !== 0);
```

The `$it !== 0` still works because the zero cursor will be represented
as an integer.  Only absurdly large (> 2^63) values are represented as a
string.

Fixes #2454
2024-03-17 10:59:14 -07:00
thomaston a3327d9d2b Fix bug: the pipeline mode socket return an unexpected result after reconnecting (#2358)
* fix bug: the pipeline mode socket return an unexpected result after reconnecting

* fix typos: pipeline is right

---------

Co-authored-by: marcofu <marcofu@tencent.com>
2023-07-20 11:48:53 -07:00
Pavlo Yatsukhnenko 2b2bc042da Merge pull request #2327 from phpredis/sentinel
Synchronize Redis and RedisSentinel constructors
2023-03-01 22:08:12 +02:00
michael-grunder ccd419a4c8 Small refactor of some methods
* Use our `redis_cmd_append_sstr_key_*` and `redis_cmd_append_sstr_zval`
  wrappers, which handle key prefixing and serialization transparently.

* Rework ZADD so it can handle the bulk double response from the `INCR`
  options.
2023-03-01 11:45:47 -08:00
Pavlo Yatsukhnenko ebb2386e52 Synchronize Redis and RedisSentinel constructors 2023-02-12 22:33:45 +02:00
Pavlo Yatsukhnenko 2908215572 Merge pull request #2306 from phpredis/issue-2068-function
Add Redis::function command
2022-12-21 22:53:16 +02:00
Pavlo Yatsukhnenko 90a0e9cc0e Add Redis::function command 2022-12-18 18:21:42 +02:00
michael-grunder 40e1b1bfe8 Migrate more command handlers to the new arg API 2022-12-11 22:37: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 27900f39d2 Implement new ZSET commands for cluster
* Implement `ZDIFF`, `ZINTER`, `ZUNION`, `ZMSCORE`, and
  `ZRANDMEMBER` for `RedisCluster`.
* Refactor `ZUNIONSTORE` command and switch to using our centralized
  zset option parsing handler.

See #1894
2022-12-02 09:11:00 -08:00
Michael Grunder fa5d1af9ff Implement GEOSEARCH and GEOSEARCHSTORE for RedisCluster. (#2277)
* Implement GEOSEARCH and GEOSEARCHSTORE for RedisCluster.

See #1894
2022-12-01 21:54:15 -08:00
michael-grunder 7121aaae5c Implement LPOS for RedisCluster
See #1894
2022-12-01 14:05:43 -08:00
michael-grunder 90828019de Refactor network IO tracking.
* Create inline wrappers of the low-level php_stream_* functions that
  also keep track of the number of bytes written/read.

* Change the logic to aggregate network traffic until the user
  explicitly "resets" it.  I think this will be a more common use-case
  (running many commands and then seeing overall network IO).

See #2106
2022-11-25 13:41:47 -08:00
Pavlo Yatsukhnenko ff863f3f97 Refactor command command
Issue #2068
2022-11-19 14:04:38 +02:00
michael-grunder 0b7bd83f57 Add more docblocks and fix XAUTOCLAIM response handler.
- Finish adding docblocks with examples for all of the stream commands.
- Fix XAUTOCLAIM response handler (the reply has a slightly different
  structure to XCLAIM.
2022-11-15 23:29:45 -08:00
Pavlo Yatsukhnenko 504810a5d1 Issue #2068, Refactor ACL command 2022-11-01 12:53:23 +02:00
Pavlo Yatsukhnenko 2a0d1c1e6d Refactor PubSub command 2022-10-31 17:01:35 -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 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 6b34d17fc4 Add new Redis 6.2.0 XTRIM options
Fixes #1961
2022-10-08 11:35:10 -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 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
Pavlo Yatsukhnenko df97cc3531 Issue #1894
Add the COUNT argument to LPOP and RPOP
2022-06-07 18:51:55 +03:00
Pavlo Yatsukhnenko e6b3fe5484 Backoff settings in constructor 2022-05-27 15:26:39 +03:00
Pavlo Yatsukhnenko fe397371ef Issue #1894
Add Redis::hRandField command
2022-04-12 22:00:04 +03:00
Pavlo Yatsukhnenko 0879770a82 Issue #1746 2022-04-05 22:56:25 +03:00