); // Kill the process at ip:port
~~~
##### *Return value*
This will vary depending on which client command was executed.
* CLIENT LIST will return an array of arrays with client information.
* CLIENT GETNAME will return the client name or false if none has been set
* CLIENT SETNAME will return true if it can be set and false if not
* CLIENT KILL will return true if the client can be killed, and false if not
Note: phpredis will attempt to reconnect so you can actually kill your own connection
but may not notice losing it!
### getLastError
-----
_**Description**_: The last error message (if any)
##### *Parameters*
*none*
##### *Return value*
A string with the last returned script based error message, or NULL if there is no error
##### *Examples*
~~~php
$redis->eval('this-is-not-lua');
$err = $redis->getLastError();
// "ERR Error compiling script (new function): user_script:1: '=' expected near '-'"
~~~
### clearLastError
-----
_**Description**_: Clear the last error message
##### *Parameters*
*none*
##### *Return value*
*BOOL* TRUE
##### *Examples*
~~~php
$redis->set('x', 'a');
$redis->incr('x');
$err = $redis->getLastError();
// "ERR value is not an integer or out of range"
$redis->clearLastError();
$err = $redis->getLastError();
// NULL
~~~
### _prefix
-----
_**Description**_: A utility method to prefix the value with the prefix setting for phpredis.
##### *Parameters*
*value* string. The value you wish to prefix
##### *Return value*
If a prefix is set up, the value now prefixed. If there is no prefix, the value will be returned unchanged.
##### *Examples*
~~~php
$redis->setOption(Redis::OPT_PREFIX, 'my-prefix:');
$redis->_prefix('my-value'); // Will return 'my-prefix:my-value'
~~~
### _serialize
-----
_**Description**_: A utility method to serialize values manually.
This method allows you to serialize a value with whatever serializer is configured, manually.
This can be useful for serialization/unserialization of data going in and out of EVAL commands
as phpredis can't automatically do this itself. Note that if no serializer is set, phpredis
will change Array values to 'Array', and Objects to 'Object'.
##### *Parameters*
*value*: Mixed. The value to be serialized
##### *Examples*
~~~php
$redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_NONE);
$redis->_serialize("foo"); // returns "foo"
$redis->_serialize([]); // Returns "Array"
$redis->_serialize(new stdClass()); // Returns "Object"
$redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP);
$redis->_serialize("foo"); // Returns 's:3:"foo";'
~~~
### _unserialize
-----
_**Description**_: A utility method to unserialize data with whatever serializer is set up.
If there is no serializer set, the value will be returned unchanged. If there is a serializer set up,
and the data passed in is malformed, an exception will be thrown. This can be useful if phpredis is
serializing values, and you return something from redis in a LUA script that is serialized.
##### *Parameters*
*value* string. The value to be unserialized
##### *Examples*
~~~php
$redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP);
$redis->_unserialize('a:3:{i:0;i:1;i:1;i:2;i:2;i:3;}'); // Will return [1,2,3]
~~~
## Introspection
### isConnected
-----
_**Description**_: A method to determine if a phpredis object thinks it's connected to a server
##### *Parameters*
None
##### *Return value*
*Boolean* Returns TRUE if phpredis thinks it's connected and FALSE if not
### getHost
-----
_**Description**_: Retrieve our host or unix socket that we're connected to
##### *Parameters*
None
##### *Return value*
*Mixed* The host or unix socket we're connected to or FALSE if we're not connected
### getPort
-----
_**Description**_: Get the port we're connected to
##### *Parameters*
None
##### *Return value*
*Mixed* Returns the port we're connected to or FALSE if we're not connected
### getDbNum
-----
_**Description**_: Get the database number phpredis is pointed to
##### *Parameters*
None
##### *Return value*
*Mixed* Returns the database number (LONG) phpredis thinks it's pointing to or FALSE if we're not connected
### getTimeout
-----
_**Description**_: Get the (write) timeout in use for phpredis
##### *Parameters*
None
##### *Return value*
*Mixed* The timeout (DOUBLE) specified in our connect call or FALSE if we're not connected
### getReadTimeout
_**Description**_: Get the read timeout specified to phpredis or FALSE if we're not connected
##### *Parameters*
None
##### *Return value*
*Mixed* Returns the read timeout (which can be set using setOption and Redis::OPT_READ_TIMEOUT) or FALSE if we're not connected
### getPersistentID
-----
_**Description**_: Gets the persistent ID that phpredis is using
##### *Parameters*
None
##### *Return value*
*Mixed* Returns the persistent id phpredis is using (which will only be set if connected with pconnect), NULL if we're not
using a persistent ID, and FALSE if we're not connected
### getAuth
-----
_**Description**_: Get the password (or username and password if using Redis 6 ACLs) used to authenticate the connection.
### *Parameters*
None
### *Return value*
*Mixed* Returns NULL if no username/password are set, the password string if a password is set, and a `[username, password]` array if authenticated with a username and password.
redis-6.0.2/INSTALL.md 0000644 0001750 0000012 00000007567 14515245367 015067 0 ustar pyatsukhnenko wheel # Installation from pecl/pickle
To pull latest stable released version, from [pecl](https://pecl.php.net/package/redis) / [pickle](https://wiki.php.net/rfc/deprecate-pear-include-composer):
~~~
pecl install redis
// If using PHP >= 7.3
pickle install redis
~~~
# Installation from sources
To build this extension for the sources tree:
~~~
git clone https://github.com/phpredis/phpredis.git
cd phpredis
phpize
./configure [--enable-redis-igbinary] [--enable-redis-msgpack] [--enable-redis-lzf [--with-liblzf[=DIR]]] [--enable-redis-zstd] [--enable-redis-lz4]
make && make install
~~~
If you would like phpredis to serialize your data using the igbinary library, run configure with `--enable-redis-igbinary`.
If you would like to use the msgpack serializer, run configure with `--enable-redis-msgpack` (note: Requires php-msgpack >= 2.0.3)
The extension also may compress data before sending it to Redis server, if you run configure with `--enable-redis-lzf`. If you want to use lzf library pre-installed into your system use `--with-liblzf` configuration option to specify the path where to search files.
`make install` copies `redis.so` to an appropriate location, but you still need to enable the module in the PHP config file. To do so, either edit your php.ini or add a redis.ini file in `/etc/php5/conf.d` with the following contents: `extension=redis.so`.
You can generate a debian package for PHP5, accessible from Apache 2 by running `./mkdeb-apache2.sh` or with `dpkg-buildpackage` or `svn-buildpackage`.
This extension exports a single class, [Redis](./README.md#class-redis) (and [RedisException](./README.md#class-redisexception) used in case of errors). Check out https://github.com/ukko/phpredis-phpdoc for a PHP stub that you can use in your IDE for code completion.
# Binary packages
Most distributions provides pre-build binary packages of this extension.
## Windows:
Follow the DLL link on the [https://pecl.php.net/package/redis](https://pecl.php.net/package/redis) page or use [https://windows.php.net/downloads/pecl/releases/redis/](https://windows.php.net/downloads/pecl/releases/redis/)
## Fedora
Fedora users can install the package from the official repository.
### Fedora ≥ 29, Version 5
Installation of the [php-pecl-redis5](https://apps.fedoraproject.org/packages/php-pecl-redis5) package:
~~~
dnf install php-pecl-redis5
~~~
## RHEL / CentOS
Installation of the [php-pecl-redis](https://apps.fedoraproject.org/packages/php-pecl-redis) package, from the [EPEL repository](https://fedoraproject.org/wiki/EPEL):
~~~
yum install php-pecl-redis
~~~
### openSUSE ≥ 15.1
Installation of the [php7-redis](https://software.opensuse.org/package/php7-redis?search_term=php7-redis) package:
~~~
zypper in php7-redis
~~~
# Installation on OSX
If the install fails on OSX, type the following commands in your shell before trying again:
~~~
MACOSX_DEPLOYMENT_TARGET=10.6
CFLAGS="-arch i386 -arch x86_64 -g -Os -pipe -no-cpp-precomp"
CCFLAGS="-arch i386 -arch x86_64 -g -Os -pipe"
CXXFLAGS="-arch i386 -arch x86_64 -g -Os -pipe"
LDFLAGS="-arch i386 -arch x86_64 -bind_at_load"
export CFLAGS CXXFLAGS LDFLAGS CCFLAGS MACOSX_DEPLOYMENT_TARGET
~~~
If that still fails and you are running Zend Server CE, try this right before "make": `./configure CFLAGS="-arch i386"`.
Taken from [Compiling phpredis on Zend Server CE/OSX ](http://www.tumblr.com/tagged/phpredis).
See also: [Install Redis & PHP Extension PHPRedis with Macports](http://www.lecloud.net/post/3378834922/install-redis-php-extension-phpredis-with-macports).
You can install it using MacPorts:
- [Get macports-php](https://www.macports.org/)
- `sudo port install php56-redis` (or php53-redis, php54-redis, php55-redis, php70-redis, php71-redis, php72-redis, php73-redis, php74-redis)
# Building on Windows
See [instructions from @char101](https://github.com/phpredis/phpredis/issues/213#issuecomment-11361242) on how to build phpredis on Windows.
redis-6.0.2/arrays.md 0000644 0001750 0000012 00000023443 14515245367 015251 0 ustar pyatsukhnenko wheel Redis Arrays
============
A Redis array is an isolated namespace in which keys are related in some manner. Keys are distributed across a number of Redis instances, using consistent hashing. A hash function is used to spread the keys across the array in order to keep a uniform distribution. **This feature was added as the result of a generous sponsorship by [A+E Networks](http://www.aetn.com/).**
An array is composed of the following:
* A list of Redis hosts.
* A key extraction function, used to hash part of the key in order to distribute related keys on the same node (optional). This is set by the "function" option.
* A list of nodes previously in the ring, only present after a node has been added or removed. When a read command is sent to the array (e.g. GET, LRANGE...), the key is first queryied in the main ring, and then in the secondary ring if it was not found in the main one. Optionally, the keys can be migrated automatically when this happens. Write commands will always go to the main ring. This is set by the "previous" option.
* An optional index in the form of a Redis set per node, used to migrate keys when nodes are added or removed; set by the "index" option.
* An option to rehash the array automatically as nodes are added or removed, set by the "autorehash" option.
## Creating an array
There are several ways of creating Redis arrays; they can be pre-defined in redis.ini using `new RedisArray(string $name);`, or created dynamically using `new RedisArray(array $hosts, array $options);`
#### Declaring a new array with a list of nodes
$ra = new RedisArray(array("host1", "host2:63792", "host2:6380"));
#### Declaring a new array with a list of nodes and a function to extract a part of the key
function extract_key_part($k) {
return substr($k, 0, 3); // hash only on first 3 characters.
}
$ra = new RedisArray(array("host1", "host2:63792", "host2:6380"), array("function" => "extract_key_part"));
#### Defining a "previous" array when nodes are added or removed.
When a new node is added to an array, phpredis needs to know about it. The old list of nodes becomes the “previous” array, and the new list of nodes is used as a main ring. Right after a node has been added, some read commands will point to the wrong nodes and will need to look up the keys in the previous ring.
// adding host3 to a ring containing host1 and host2. Read commands will look in the previous ring if the data is not found in the main ring.
$ra = new RedisArray(array("host1", "host2", "host3"), array("previous" => array("host1", "host2")));
#### Specifying the "retry_interval" parameter
The retry_interval is used to specify a delay in milliseconds between reconnection attempts in case the client loses connection with a server
$ra = new RedisArray(array("host1", "host2:63792", "host2:6380"), array("retry_timeout" => 100));
#### Specifying the "lazy_connect" parameter
This option is useful when a cluster has many shards but not of them are necessarily used at one time.
$ra = new RedisArray(array("host1", "host2:63792", "host2:6380"), array("lazy_connect" => true));
#### Specifying the "connect_timeout" parameter
The connect_timeout value is a double and is used to specify a timeout in number of seconds when creating redis socket connections used in the RedisArray.
$ra = new RedisArray(array("host1", "host2:63792", "host2:6380"), array("connect_timeout" => 0.5));
#### Specifying the "read_timeout" parameter
The read_timeout value is a double and is used to specify a timeout in number of seconds when waiting response from the server.
$ra = new RedisArray(array("host1", "host2:63792", "host2:6380"), array("read_timeout" => 0.5));
#### Specifying the "algorithm" parameter
The algorithm value is a string and is used to specify the name of key hashing algorithm. The list of possible values may be found using PHP function `hash_algos`.
If algorithm is not supported by PHP `hash` function default algorithm will be used (CRC32 with 0xffffffff initial value).
$ra = new RedisArray(array("host1", "host2:63792", "host2:6380"), array("algorithm" => "md5"));
#### Specifying the "consistent" parameter
The value is boolean. When enabled RedisArray uses "ketama" distribution algorithm (currently without ability to set weight to each server).
This option applies to main and previous ring if specified.
$ra = new RedisArray(array("host1", "host2:63792", "host2:6380"), array("consistent" => true));
#### Specifying the "auth" parameter
The value is string and used to specify the password for authenticate with the server prior to sending commands
$ra = new RedisArray(array("host1", "host2:63792", "host2:6380"), array("auth" => "mysecretpassword"));
#### Defining arrays in Redis.ini
Because php.ini parameters must be pre-defined, Redis Arrays must all share the same .ini settings.
// list available Redis Arrays
ini_set('redis.array.names', 'users,friends');
// set host names for each array.
ini_set('redis.arrays.hosts', 'users[]=localhost:6379&users[]=localhost:6380&users[]=localhost:6381&users[]=localhost:6382&friends[]=localhost');
// set functions
ini_set('redis.arrays.functions', 'users=user_hash');
// use index only for users
ini_set('redis.arrays.index', 'users=1,friends=0');
// use password for authentication
ini_set('redis.arrays.auth', 'users=mysecretpassword')
## Usage
Redis arrays can be used just as Redis objects:
$ra = new RedisArray("users");
$ra->set("user1:name", "Joe");
$ra->set("user2:name", "Mike");
## Key hashing
By default and in order to be compatible with other libraries, phpredis will try to find a substring enclosed in curly braces within the key name, and use it to distribute the data.
For instance, the keys “{user:1}:name” and “{user:1}:email” will be stored on the same server as only “user:1” will be hashed. You can provide a custom function name in your redis array with the "function" option; this function will be called every time a key needs to be hashed. It should take a string and return a string.
## Custom key distribution function
In order to control the distribution of keys by hand, you can provide a custom function or closure that returns the server number, which is the index in the array of servers that you created the RedisArray object with.
For instance, instantiate a RedisArray object with `new RedisArray(array("us-host", "uk-host", "de-host"), array("distributor" => "dist"));` and write a function called "dist" that will return `2` for all the keys that should end up on the "de-host" server.
### Example
$ra = new RedisArray(array("host1", "host2", "host3", "host4", "host5", "host6", "host7", "host8"), array("distributor" => array(2, 2)));
This declares that we started with 2 shards and moved to 4 then 8 shards. The number of initial shards is 2 and the resharding level (or number of iterations) is 2.
## Migrating keys
When a node is added or removed from a ring, RedisArray instances must be instantiated with a “previous” list of nodes. A single call to `$ra->_rehash()` causes all the keys to be redistributed according to the new list of nodes. Passing a callback function to `_rehash()` makes it possible to track the progress of that operation: the function is called with a node name and a number of keys that will be examined, e.g. `_rehash(function ($host, $count){ ... });`.
It is possible to automate this process, by setting `'autorehash' => TRUE` in the constructor options. This will cause keys to be migrated when they need to be read from the previous array.
In order to migrate keys, they must all be examined and rehashed. If the "index" option was set, a single key per node lists all keys present there. Otherwise, the `KEYS` command is used to list them.
If a “previous” list of servers is provided, it will be used as a backup ring when keys can not be found in the current ring. Writes will always go to the new ring, whilst reads will go to the new ring first, and to the second ring as a backup.
Adding and/or removing several instances is supported.
### Example
$ra = new RedisArray("users"); // load up a new config from redis.ini, using the “.previous” listing.
$ra->_rehash();
Running this code will:
* Create a new ring with the updated list of nodes.
* Server by server, look up all the keys in the previous list of nodes.
* Rehash each key and possibly move it to another server.
* Update the array object with the new list of nodes.
## Multi/exec
Multi/exec is still available, but must be run on a single node:
$host = $ra->_target("{users}:user1:name"); // find host first
$ra->multi($host) // then run transaction on that host.
->del("{users}:user1:name")
->srem("{users}:index", "user1")
->exec();
## Limitations
Key arrays offer no guarantee when using Redis commands that span multiple keys. Except for the use of MGET, MSET, and DEL, a single connection will be used and all the keys read or written there. Running KEYS() on a RedisArray object will execute the command on each node and return an associative array of keys, indexed by host name.
## Array info
RedisArray objects provide several methods to help understand the state of the cluster. These methods start with an underscore.
* `$ra->_hosts()` → returns a list of hosts for the selected array.
* `$ra->_function()` → returns the name of the function used to extract key parts during consistent hashing.
* `$ra->_target($key)` → returns the host to be used for a certain key.
* `$ra->_instance($host)` → returns a redis instance connected to a specific node; use with `_target` to get a single Redis object.
* `$ra->_continuum()` → returns a list of points on continuum; may be useful with custom distributor function.
## Running the unit tests
$ cd tests
$ ./mkring.sh start
$ php array-tests.php
redis-6.0.2/cluster.md 0000644 0001750 0000012 00000027370 14515245367 015434 0 ustar pyatsukhnenko wheel Redis Cluster
=============
Redis introduces cluster support as of version 3.0.0, and to communicate with a cluster using phpredis one needs to use the RedisCluster class. For the majority of operations the RedisCluster class can act as a drop-in replacement for the Redis class without needing to modify how it's called. **This feature was added as the result of a generous sponsorship by [Tradesy](https://www.tradesy.com/)**
## Creating and connecting to a cluster
To maintain consistency with the RedisArray class, one can create and connect to a cluster either by passing it one or more 'seed' nodes, or by defining these in redis.ini as a 'named' cluster.
#### Declaring a cluster with an array of seeds
```php
// Create a cluster setting three nodes as seeds
$obj_cluster = new RedisCluster(NULL, Array('host:7000', 'host:7001', 'host:7003'));
// Connect and specify timeout and read_timeout
$obj_cluster = new RedisCluster(NULL, Array("host:7000", "host:7001"), 1.5, 1.5);
// Connect with read/write timeout as well as specify that phpredis should use
// persistent connections to each node.
$obj_cluster = new RedisCluster(NULL, Array("host:7000", "host:7001"), 1.5, 1.5, true);
// Connect with cluster using password.
$obj_cluster = new RedisCluster(NULL, Array("host:7000", "host:7001"), 1.5, 1.5, true, "password");
// Connect with cluster using SSL/TLS
// last argument is an array with [SSL context](https://www.php.net/manual/en/context.ssl.php) options
$obj_cluster = new RedisCluster(NULL, Array("host:7000", "host:7001"), 1.5, 1.5, true, NULL, Array("verify_peer" => false));
```
#### Loading a cluster configuration by name
In order to load a named array, one must first define the seed nodes in redis.ini. The following lines would define the cluster 'mycluster', and be loaded automatically by phpredis.
```ini
# In redis.ini
redis.clusters.seeds = "mycluster[]=localhost:7000&test[]=localhost:7001"
redis.clusters.timeout = "mycluster=5"
redis.clusters.read_timeout = "mycluster=10"
redis.clusters.auth = "mycluster=password"
```
Then, this cluster can be loaded by doing the following
```php
$obj_cluster = new RedisCluster('mycluster');
```
## Connection process
On construction, the RedisCluster class will iterate over the provided seed nodes until it can attain a connection to the cluster and run CLUSTER SLOTS to map every node in the cluster locally. Once the keyspace is mapped, RedisCluster will only connect to nodes when it needs to (e.g. you're getting a key that we believe is on that node.)
## Slot caching
Each time the `RedisCluster` class is constructed from scratch, phpredis needs to execute a `CLUSTER SLOTS` command to map the keyspace. Although this isn't an expensive command, it does require a round trip for each newly created object, which is inefficient. Starting from PhpRedis 5.0.0 these slots can be cached by setting `redis.clusters.cache_slots = 1` in `php.ini`.
## Timeouts
Because Redis cluster is intended to provide high availability, timeouts do not work in the same way they do in normal socket communication. It's fully possible to have a timeout or even exception on a given socket (say in the case that a master node has failed), and continue to serve the request if and when a slave can be promoted as the new master.
The way RedisCluster handles user specified timeout values is that every time a command is sent to the cluster, we record the time at the start of the request and then again every time we have to re-issue the command to a different node (either because Redis cluster responded with MOVED/ASK or because we failed to communicate with a given node). Once we detect having been in the command loop for longer than our specified timeout, an error is raised.
## Keyspace map
As previously described, RedisCluster makes an initial mapping of every master (and any slaves) on construction, which it uses to determine which nodes to direct a given command. However, one of the core functionalities of Redis cluster is that this keyspace can change while the cluster is running.
Because of this, the RedisCluster class will update its keyspace mapping whenever it receives a MOVED error when requesting data. In the case that we receive ASK redirection, it follows the Redis specification and requests the key from the ASK node, prefixed with an ASKING command.
## Automatic slave failover / distribution
By default, RedisCluster will only ever send commands to master nodes, but can be configured differently for readonly commands if requested.
```php
// The default option, only send commands to master nodes
$obj_cluster->setOption(RedisCluster::OPT_SLAVE_FAILOVER, RedisCluster::FAILOVER_NONE);
// In the event we can't reach a master, and it has slaves, failover for read commands
$obj_cluster->setOption(RedisCluster::OPT_SLAVE_FAILOVER, RedisCluster::FAILOVER_ERROR);
// Always distribute readonly commands between masters and slaves, at random
$obj_cluster->setOption(
RedisCluster::OPT_SLAVE_FAILOVER, RedisCluster::FAILOVER_DISTRIBUTE
);
// Always distribute readonly commands to the slaves, at random
$obj_cluster->setOption(
RedisCluster::OPT_SLAVE_FAILOVER, RedisCluster::FAILOVER_DISTRIBUTE_SLAVES
);
```
## Main command loop
With the exception of commands that are directed to a specific node, each command executed via RedisCluster is processed through a command loop, where we make the request, handle any MOVED or ASK redirection, and repeat if necessary. This continues until one of the following conditions is met:
1. We fail to communicate with *any* node that we are aware of, in which case a `RedisClusterException` is raised.
2. We have been bounced around longer than the timeout which was set on construction.
3. Redis cluster returns to us a `CLUSTERDOWN` error, in which case a `RedisClusterException` is raised.
4. We receive a valid response, in which case the data is returned to the caller.
## Transactions
The RedisCluster class fully supports MULTI ... EXEC transactions, including commands such as MGET and MSET which operate on multiple keys. There are considerations that must be taken into account here however.
When you call `RedisCluster->multi()`, the cluster is put into a MULTI state, but the MULTI command is not delivered to any nodes until a key is requested on that node. In addition, calls to EXEC will always return an array (even in the event that a transaction to a given node failed), as the commands can be going to any number of nodes depending on what is called.
Consider the following example:
```php
// Cluster is put into MULTI state locally
$obj_cluster->multi();
// The cluster will issue MULTI on this node first (and only once)
$obj_cluster->get("mykey");
$obj_cluster->set("mykey", "new_value");
// If 'myotherkey' maps to a different node, MULTI will be issued there
// before requesting the key
$obj_cluster->get("myotherkey");
// This will always return an array, even in the event of a failed transaction
// on one of the nodes, in which case that element will be FALSE
print_r($obj_cluster->exec());
```
## Pipelining
The RedisCluster class does not support pipelining as there is no way to detect whether the keys still live where our map indicates that they do and would therefore be inherently unsafe. It would be possible to implement this support as an option if there is demand for such a feature.
## Multiple key commands
Redis cluster does allow commands that operate on multiple keys, but only if all of those keys hash to the same slot. Note that it is not enough that the keys are all on the same node, but must actually hash to the exact same hash slot.
For all of these multiple key commands (with the exception of MGET and MSET), the RedisCluster class will verify each key maps to the same hash slot and raise a "CROSSSLOT" warning, returning false if they don't.
### MGET, MSET, DEL, and UNLINK
RedisCluster has specialized processing for MGET, MSET, DEL, and UNLINK which allows you to send any number of keys (hashing to whichever slots) without having to consider where they live. The way this works, is that the RedisCluster class will split the command as it iterates through keys, delivering a subset of commands per each key's slot.
*Note: If you send keys that hash to more than one slot, these commands are no longer atomic.*
```php
// This will send two `MGET` commands. One for `{hash1}` keys, and one for `otherkey`
$obj_cluster->mget(["{hash1}key1","{hash1}key2","{hash1}key3","otherkey"]);
```
This operation can also be done in MULTI mode transparently.
## Directed node commands
There are a variety of commands which have to be directed at a specific node. In the case of these commands, the caller can either pass a key (which will be hashed and used to direct our command), or an array with host:port.
```php
// This will be directed at the slot/node which would store "mykey"
$obj_cluster->echo("mykey","Hello World!");
// Here we're iterating all of our known masters, and delivering the command there
foreach ($obj_cluster->_masters() as $arr_master) {
$obj_cluster->echo($arr_master, "Hello: " . implode(':', $arr_master));
}
```
In the case of all commands which need to be directed at a node, the calling convention is identical to the Redis call, except that they require an additional (first) argument in order to deliver the command. Following is a list of each of these commands:
1. ACL
1. BGREWRITEAOF
1. BGSAVE
1. CLIENT
1. CLUSTER
1. CONFIG
1. DBSIZE
1. ECHO
1. FLUSHALL
1. FLUSHDB
1. INFO
1. LASTSAVE
1. PING
1. PUBSUB
1. RANDOMKEY
1. RAWCOMMAND
1. ROLE
1. SAVE
1. SCAN
1. SCRIPT
1. SLOWLOG
1. TIME
## Session Handler
You can use the cluster functionality of phpredis to store PHP session information in a Redis cluster as you can with a non cluster-enabled Redis instance.
To do this, you must configure your `session.save_handler` and `session.save_path` INI variables to give phpredis enough information to communicate with the cluster.
```ini
session.save_handler = rediscluster
session.save_path = "seed[]=host1:port1&seed[]=host2:port2&seed[]=hostN:portN&timeout=2&read_timeout=2&failover=error&persistent=1&auth=password&stream[verify_peer]=0"
```
### session.session_handler
Set this variable to "rediscluster" to inform phpredis that this is a cluster instance.
### session.save_path
The save path for cluster based session storage takes the form of a PHP GET request, and requires that you specify at least one `seed` node. Other options you can specify are as follows:
* _timeout (double)_: The amount of time phpredis will wait when connecting or writing to the cluster.
* _read\_timeout (double)_: The amount of time phpredis will wait for a result from the cluster.
* _persistent_: Tells phpredis whether persistent connections should be used.
* _failover (string)_: How phpredis should distribute session reads between master and slave nodes.
* _none_ : phpredis will only communicate with master nodes
* _error_: phpredis will communicate with master nodes unless one fails, in which case an attempt will be made to read session information from a slave.
* _distribute_: phpredis will randomly distribute session reads between masters and any attached slaves (load balancing).
* _auth (string, empty by default)_: The password used to authenticate with the server prior to sending commands.
* _stream (array)_: ssl/tls stream context options.
### redis.session.early_refresh
Under normal operation, the client will refresh the session's expiry ttl whenever the session is closed. However, we can save this additional round-trip by updating the ttl when the session is opened instead ( This means that sessions that have not been modified will not send further commands to the server ).
To enable, set the following INI variable:
```ini
redis.session.early_refresh = 1
```
Note: This is disabled by default since it may significantly reduce the session lifetime for long-running scripts. Redis server version 6.2+ required.
redis-6.0.2/sentinel.md 0000644 0001750 0000012 00000017076 14515245367 015576 0 ustar pyatsukhnenko wheel Redis Sentinel
==============
Redis Sentinel provides high availability for Redis. In practical terms this means that using Sentinel you can create a Redis deployment that resists without human intervention certain kinds of failures.
Redis Sentinel also provides other collateral tasks such as monitoring, notifications and acts as a configuration provider for clients.
## Class RedisSentinel
-----
##### *Parameters*
*host*: String, IP address or hostname
*port*: Int (optional, default is 26379)
*timeout*: Float, value in seconds (optional, default is 0 meaning unlimited)
*persistent*: String, persistent connection id (optional, default is NULL meaning not persistent)
*retry_interval*: Int, value in milliseconds (optional, default is 0)
*read_timeout*: Float, value in seconds (optional, default is 0 meaning unlimited)
*auth*:String, or an Array with one or two elements, used to authenticate with the redis-sentinel. (optional, default is NULL meaning NOAUTH)
##### *Examples for version 6.0 or later*
~~~php
$sentinel = new RedisSentinel([
'host' => '127.0.0.1',
]); // default parameters
$sentinel = new RedisSentinel([
'host' => '127.0.0.1',
'port' => 26379,
'connectTimeout' => 2.5,
]); // 2.5 sec timeout.
$sentinel = new RedisSentinel([
'host' => '127.0.0.1',
'port' => 26379,
'connectTimeout' => 2.5,
'persistent' => 'sentinel',
]); // persistent connection with id 'sentinel'
$sentinel = new RedisSentinel([
'host' => '127.0.0.1',
'port' => 26379,
'connectTimeout' => 2.5,
'persistent' => '',
]); // also persistent connection with id ''
$sentinel = new RedisSentinel([
'host' => '127.0.0.1',
'port' => 26379,
'connectTimeout' => 1,
'persistent' => null,
'retryInterval' => 100,
]); // 1 sec timeout, 100ms delay between reconnection attempts.
$sentinel = new RedisSentinel([
'host' => '127.0.0.1',
'port' => 26379,
'connectTimeout' => 0,
'persistent' => null,
'retryInterval' => 0,
'readTimeout' => 0,
'auth' => 'secret',
]); // connect sentinel with password authentication
~~~
##### *Examples for versions older than 6.0*
~~~php
$sentinel = new RedisSentinel('127.0.0.1'); // default parameters
$sentinel = new RedisSentinel('127.0.0.1', 26379, 2.5); // 2.5 sec timeout.
$sentinel = new RedisSentinel('127.0.0.1', 26379, 0, 'sentinel'); // persistent connection with id 'sentinel'
$sentinel = new RedisSentinel('127.0.0.1', 26379, 0, ''); // also persistent connection with id ''
$sentinel = new RedisSentinel('127.0.0.1', 26379, 1, null, 100); // 1 sec timeout, 100ms delay between reconnection attempts.
$sentinel = new RedisSentinel('127.0.0.1', 26379, 0, NULL, 0, 0, "secret"); // connect sentinel with password authentication
~~~
### Usage
-----
* [ckquorum](#ckquorum) - Check if the current Sentinel configuration is able to reach the quorum needed to failover.
* [failover](#failover) - Force a failover as if the master was not reachable.
* [flushconfig](#flushconfig) - Force Sentinel to rewrite its configuration on disk.
* [getMasterAddrByName](#getMasterAddrByName) - Return the ip and port number of the master with that name.
* [master](#master) - Return the state and info of the specified master.
* [masters](#masters) - Return a list of monitored masters and their state.
* [ping](#ping) - Ping the sentinel.
* [reset](#reset) - Reset all the masters with matching name.
* [sentinels](#sentinels) - Return a list of sentinel instances for this master, and their state.
* [slaves](#slaves) - Return a list of replicas for this master, and their state.
-----
### ckquorum
-----
_**Description**_: Check if the current Sentinel configuration is able to reach the quorum needed to failover a master, and the majority needed to authorize the failover. This command should be used in monitoring systems to check if a Sentinel deployment is ok.
##### *Parameters*
*String*: master name
##### *Return value*
*Bool*: `TRUE` in case of success, `FALSE` in case of failure.
##### *Example*
~~~php
$sentinel->ckquorum('mymaster');
~~~
### failover
-----
_**Description**_: Force a failover as if the master was not reachable, and without asking for agreement to other Sentinels (however a new version of the configuration will be published so that the other Sentinels will update their configurations).
##### *Parameters*
*String*: master name
##### *Return value*
*Bool*: `TRUE` in case of success, `FALSE` in case of failure.
##### *Example*
~~~php
$sentinel->failover('mymaster');
~~~
### flushconfig
-----
_**Description**_: Force Sentinel to rewrite its configuration on disk, including the current Sentinel state. Normally Sentinel rewrites the configuration every time something changes in its state (in the context of the subset of the state which is persisted on disk across restart). However sometimes it is possible that the configuration file is lost because of operation errors, disk failures, package upgrade scripts or configuration managers. In those cases a way to to force Sentinel to rewrite the configuration file is handy. This command works even if the previous configuration file is completely missing.
##### *Parameters*
(none)
##### *Return value*
*Bool*: `TRUE` in case of success, `FALSE` in case of failure.
##### *Example*
~~~php
$sentinel->flushconfig();
~~~
### getMasterAddrByName
-----
_**Description**_: Return the ip and port number of the master with that name. If a failover is in progress or terminated successfully for this master it returns the address and port of the promoted replica.
##### *Parameters*
*String*: master name
##### *Return value*
*Array*, *Bool*: ['address', 'port'] in case of success, `FALSE` in case of failure.
##### *Example*
~~~php
$sentinel->getMasterAddrByName('mymaster');
~~~
### master
-----
_**Description**_: Return the state and info of the specified master.
##### *Parameters*
*String*: master name
##### *Return value*
*Array*, *Bool*: Associative array with info in case of success, `FALSE` in case of failure.
##### *Example*
~~~php
$sentinel->master('mymaster');
~~~
### masters
-----
_**Description**_: Return a list of monitored masters and their state.
##### *Parameters*
(none)
##### *Return value*
*Array*, *Bool*: List of arrays with info for each master in case of success, `FALSE` in case of failure.
##### *Example*
~~~php
$sentinel->masters();
~~~
### ping
-----
_**Description**_: Ping the sentinel.
##### *Parameters*
(none)
##### *Return value*
*Bool*: `TRUE` in case of success, `FALSE` in case of failure.
##### *Example*
~~~php
$sentinel->ping();
~~~
### reset
-----
_**Description**_: This command will reset all the masters with matching name. The pattern argument is a glob-style pattern. The reset process clears any previous state in a master (including a failover in progress), and removes every replica and sentinel already discovered and associated with the master.
##### *Parameters*
*String*: pattern
##### *Return value*
*Bool*: `TRUE` in case of success, `FALSE` in case of failure.
##### *Example*
~~~php
$sentinel->reset('*');
~~~
### sentinels
-----
_**Description**_: Return a list of sentinel instances for this master, and their state.
##### *Parameters*
*String*: master name
##### *Return value*
*Array*, *Bool*: List of arrays with info for each sentinels in case of success, `FALSE` in case of failure.
##### *Example*
~~~php
$sentinel->sentinels('mymaster');
~~~
### slaves
-----
_**Description**_: Return a list of replicas for this master, and their state.
##### *Parameters*
*String*: master name
##### *Return value*
*Array*, *Bool*: List of arrays with info for each replicas in case of success, `FALSE` in case of failure.
##### *Example*
~~~php
$sentinel->slaves('mymaster');
~~~
redis-6.0.2/backoff.c 0000644 0001750 0000012 00000005711 14515245367 015163 0 ustar pyatsukhnenko wheel #include "common.h"
#include
#if PHP_VERSION_ID >= 70100
#include
#else
static zend_long php_mt_rand_range(zend_long min, zend_long max) {
zend_long number = php_rand();
RAND_RANGE(number, min, max, PHP_RAND_MAX);
return number;
}
#endif
#include "backoff.h"
static zend_ulong random_range(zend_ulong min, zend_ulong max) {
if (max < min) {
return php_mt_rand_range(max, min);
}
return php_mt_rand_range(min, max);
}
static zend_ulong redis_default_backoff(struct RedisBackoff *self, unsigned int retry_index) {
zend_ulong backoff = retry_index ? self->base : random_range(0, self->base);
return MIN(self->cap, backoff);
}
static zend_ulong redis_constant_backoff(struct RedisBackoff *self, unsigned int retry_index) {
zend_ulong backoff = self->base;
return MIN(self->cap, backoff);
}
static zend_ulong redis_uniform_backoff(struct RedisBackoff *self, unsigned int retry_index) {
zend_ulong backoff = random_range(0, self->base);
return MIN(self->cap, backoff);
}
static zend_ulong redis_exponential_backoff(struct RedisBackoff *self, unsigned int retry_index) {
zend_ulong pow = MIN(retry_index, 10);
zend_ulong backoff = self->base * (1 << pow);
return MIN(self->cap, backoff);
}
static zend_ulong redis_full_jitter_backoff(struct RedisBackoff *self, unsigned int retry_index) {
zend_ulong pow = MIN(retry_index, 10);
zend_ulong backoff = self->base * (1 << pow);
zend_ulong cap = MIN(self->cap, backoff);
return random_range(0, cap);
}
static zend_ulong redis_equal_jitter_backoff(struct RedisBackoff *self, unsigned int retry_index) {
zend_ulong pow = MIN(retry_index, 10);
zend_ulong backoff = self->base * (1 << pow);
zend_ulong temp = MIN(self->cap, backoff);
return temp / 2 + random_range(0, temp) / 2;
}
static zend_ulong redis_decorrelated_jitter_backoff(struct RedisBackoff *self, unsigned int retry_index) {
self->previous_backoff = random_range(self->base, self->previous_backoff * 3);
return MIN(self->cap, self->previous_backoff);
}
typedef zend_ulong (*redis_backoff_algorithm)(struct RedisBackoff *self, unsigned int retry_index);
static redis_backoff_algorithm redis_backoff_algorithms[REDIS_BACKOFF_ALGORITHMS] = {
redis_default_backoff,
redis_decorrelated_jitter_backoff,
redis_full_jitter_backoff,
redis_equal_jitter_backoff,
redis_exponential_backoff,
redis_uniform_backoff,
redis_constant_backoff,
};
void redis_initialize_backoff(struct RedisBackoff *self, unsigned long retry_interval) {
self->algorithm = 0; // default backoff
self->base = retry_interval;
self->cap = retry_interval;
self->previous_backoff = 0;
}
void redis_backoff_reset(struct RedisBackoff *self) {
self->previous_backoff = 0;
}
zend_ulong redis_backoff_compute(struct RedisBackoff *self, unsigned int retry_index) {
return redis_backoff_algorithms[self->algorithm](self, retry_index);
}
redis-6.0.2/backoff.h 0000644 0001750 0000012 00000001231 14515245367 015161 0 ustar pyatsukhnenko wheel #ifndef REDIS_BACKOFF_H
#define REDIS_BACKOFF_H
/* {{{ struct RedisBackoff */
struct RedisBackoff {
unsigned int algorithm; /* index of algorithm function, returns backoff in microseconds*/
zend_ulong base; /* base backoff in microseconds */
zend_ulong cap; /* max backoff in microseconds */
zend_ulong previous_backoff; /* previous backoff in microseconds */
};
/* }}} */
void redis_initialize_backoff(struct RedisBackoff *self, unsigned long retry_interval);
void redis_backoff_reset(struct RedisBackoff *self);
zend_ulong redis_backoff_compute(struct RedisBackoff *self, unsigned int retry_index);
#endif
redis-6.0.2/cluster_library.c 0000644 0001750 0000012 00000274035 14515245367 017004 0 ustar pyatsukhnenko wheel #include "php_redis.h"
#include "common.h"
#include "library.h"
#include "redis_commands.h"
#include "cluster_library.h"
#include "crc16.h"
#include
extern zend_class_entry *redis_cluster_exception_ce;
int le_cluster_slot_cache;
/* Debugging methods/
static void cluster_dump_nodes(redisCluster *c) {
redisClusterNode *p;
ZEND_HASH_FOREACH_PTR(c->nodes, p) {
if (p == NULL) {
continue;
}
const char *slave = (p->slave) ? "slave" : "master";
php_printf("%d %s %d %d", p->sock->port, slave,p->sock->prefix_len,
p->slot);
php_printf("\n");
} ZEND_HASH_FOREACH_END();
}
static void cluster_log(char *fmt, ...)
{
va_list args;
char buffer[1024];
va_start(args, fmt);
vsnprintf(buffer,sizeof(buffer),fmt,args);
va_end(args);
fprintf(stderr, "%s\n", buffer);
}
// Debug function to dump a clusterReply structure recursively
static void dump_reply(clusterReply *reply, int indent) {
smart_string buf = {0};
int i;
switch(reply->type) {
case TYPE_ERR:
smart_string_appendl(&buf, "(error) ", sizeof("(error) ")-1);
smart_string_appendl(&buf, reply->str, reply->len);
break;
case TYPE_LINE:
smart_string_appendl(&buf, reply->str, reply->len);
break;
case TYPE_INT:
smart_string_appendl(&buf, "(integer) ", sizeof("(integer) ")-1);
smart_string_append_long(&buf, reply->integer);
break;
case TYPE_BULK:
smart_string_appendl(&buf,"\"", 1);
smart_string_appendl(&buf, reply->str, reply->len);
smart_string_appendl(&buf, "\"", 1);
break;
case TYPE_MULTIBULK:
if (reply->elements < 0) {
smart_string_appendl(&buf, "(nil)", sizeof("(nil)")-1);
} else {
for (i = 0; i < reply->elements; i++) {
dump_reply(reply->element[i], indent+2);
}
}
break;
default:
break;
}
if (buf.len > 0) {
for (i = 0; i < indent; i++) {
php_printf(" ");
}
smart_string_0(&buf);
php_printf("%s", buf.c);
php_printf("\n");
efree(buf.c);
}
}
*/
/* Recursively free our reply object. If free_data is non-zero we'll also free
* the payload data (strings) themselves. If not, we just free the structs */
void cluster_free_reply(clusterReply *reply, int free_data) {
long long i;
switch(reply->type) {
case TYPE_ERR:
case TYPE_LINE:
case TYPE_BULK:
if (free_data && reply->str)
efree(reply->str);
break;
case TYPE_MULTIBULK:
if (reply->element) {
if (reply->elements > 0) {
for (i = 0; i < reply->elements && reply->element[i]; i++) {
cluster_free_reply(reply->element[i], free_data);
}
}
efree(reply->element);
}
break;
default:
break;
}
efree(reply);
}
static int
cluster_multibulk_resp_recursive(RedisSock *sock, size_t elements,
clusterReply **element, int status_strings)
{
int i;
size_t sz;
clusterReply *r;
long len;
char buf[1024];
for (i = 0; i < elements; i++) {
r = element[i] = ecalloc(1, sizeof(clusterReply));
// Bomb out, flag error condition on a communication failure
if (redis_read_reply_type(sock, &r->type, &len) < 0) {
return FAILURE;
}
/* Set our reply len */
r->len = len;
switch(r->type) {
case TYPE_ERR:
case TYPE_LINE:
if (redis_sock_gets(sock,buf,sizeof(buf),&sz) < 0) {
return FAILURE;
}
r->len = (long long)sz;
if (status_strings) r->str = estrndup(buf, r->len);
break;
case TYPE_INT:
r->integer = len;
break;
case TYPE_BULK:
if (r->len >= 0) {
r->str = redis_sock_read_bulk_reply(sock,r->len);
if (!r->str) {
return FAILURE;
}
}
break;
case TYPE_MULTIBULK:
r->elements = r->len;
if (r->elements > 0) {
r->element = ecalloc(r->len, sizeof(*r->element));
if (cluster_multibulk_resp_recursive(sock, r->elements, r->element, status_strings) < 0) {
return FAILURE;
}
}
break;
default:
return FAILURE;
}
}
return SUCCESS;
}
/* Return the socket for a slot and slave index */
static RedisSock *cluster_slot_sock(redisCluster *c, unsigned short slot,
zend_ulong slaveidx)
{
redisClusterNode *node;
/* Return the master if we're not looking for a slave */
if (slaveidx == 0) {
return SLOT_SOCK(c, slot);
}
/* Abort if we can't find this slave */
if (!SLOT_SLAVES(c, slot) ||
(node = zend_hash_index_find_ptr(SLOT_SLAVES(c,slot), slaveidx)) == NULL
) {
return NULL;
}
/* Success, return the slave */
return node->sock;
}
/* Read the response from a cluster */
clusterReply *cluster_read_resp(redisCluster *c, int status_strings) {
return cluster_read_sock_resp(c->cmd_sock, c->reply_type,
status_strings ? c->line_reply : NULL,
c->reply_len);
}
/* Read any sort of response from the socket, having already issued the
* command and consumed the reply type and meta info (length) */
clusterReply*
cluster_read_sock_resp(RedisSock *redis_sock, REDIS_REPLY_TYPE type,
char *line_reply, long long len)
{
clusterReply *r;
r = ecalloc(1, sizeof(clusterReply));
r->type = type;
switch(r->type) {
case TYPE_INT:
r->integer = len;
break;
case TYPE_LINE:
if (line_reply) {
r->str = estrndup(line_reply, len);
r->len = len;
}
REDIS_FALLTHROUGH;
case TYPE_ERR:
return r;
case TYPE_BULK:
r->len = len;
r->str = redis_sock_read_bulk_reply(redis_sock, len);
if (r->len != -1 && !r->str) {
cluster_free_reply(r, 1);
return NULL;
}
break;
case TYPE_MULTIBULK:
r->elements = len;
if (r->elements > 0) {
r->element = ecalloc(len, sizeof(clusterReply*));
if (cluster_multibulk_resp_recursive(redis_sock, len, r->element, line_reply != NULL) < 0) {
cluster_free_reply(r, 1);
return NULL;
}
}
break;
default:
cluster_free_reply(r, 1);
return NULL;
}
// Success, return the reply
return r;
}
/*
* Helpers to send various 'control type commands to a specific node, e.g.
* MULTI, ASKING, READONLY, READWRITE, etc
*/
/* Send a command to the specific socket and validate reply type */
static int cluster_send_direct(RedisSock *redis_sock, char *cmd, int cmd_len,
REDIS_REPLY_TYPE type)
{
char buf[1024];
/* Connect to the socket if we aren't yet and send our command, validate the reply type, and consume the first line */
if (!CLUSTER_SEND_PAYLOAD(redis_sock,cmd,cmd_len) ||
!CLUSTER_VALIDATE_REPLY_TYPE(redis_sock, type) ||
!redis_sock_gets_raw(redis_sock, buf, sizeof(buf))) return -1;
/* Success! */
return 0;
}
static int cluster_send_asking(RedisSock *redis_sock) {
return cluster_send_direct(redis_sock, ZEND_STRL(RESP_ASKING_CMD), TYPE_LINE);
}
/* Send READONLY to a specific RedisSock unless it's already flagged as being
* in READONLY mode. If we can send the command, we flag the socket as being
* in that mode. */
static int cluster_send_readonly(RedisSock *redis_sock) {
int ret;
/* We don't have to do anything if we're already in readonly mode */
if (redis_sock->readonly) return 0;
/* Return success if we can send it */
ret = cluster_send_direct(redis_sock, ZEND_STRL(RESP_READONLY_CMD), TYPE_LINE);
/* Flag this socket as READONLY if our command worked */
redis_sock->readonly = !ret;
/* Return the result of our send */
return ret;
}
/* Send MULTI to a specific ReidsSock */
static int cluster_send_multi(redisCluster *c, short slot) {
if (cluster_send_direct(SLOT_SOCK(c,slot), ZEND_STRL(RESP_MULTI_CMD), TYPE_LINE) == 0) {
c->flags->txBytes += sizeof(RESP_MULTI_CMD) - 1;
c->cmd_sock->mode = MULTI;
return 0;
}
return -1;
}
/* Send EXEC to a given slot. We can use the normal command processing mechanism
* here because we know we'll only have sent MULTI to the master nodes. We can't
* failover inside a transaction, as we don't know if the transaction will only
* be readonly commands, or contain write commands as well */
PHP_REDIS_API int cluster_send_exec(redisCluster *c, short slot) {
int retval;
/* Send exec */
retval = cluster_send_slot(c, slot, ZEND_STRL(RESP_EXEC_CMD), TYPE_MULTIBULK);
/* We'll either get a length corresponding to the number of commands sent to
* this node, or -1 in the case of EXECABORT or WATCH failure. */
c->multi_len[slot] = c->reply_len > 0 ? 1 : -1;
/* Return our retval */
return retval;
}
PHP_REDIS_API int cluster_send_discard(redisCluster *c, short slot) {
if (cluster_send_direct(SLOT_SOCK(c,slot), ZEND_STRL(RESP_DISCARD_CMD), TYPE_LINE))
{
return 0;
}
return -1;
}
/*
* Cluster key distribution helpers. For a small handlful of commands, we want
* to distribute them across 1-N nodes. These methods provide simple containers
* for the purposes of splitting keys/values in this way
* */
/* Free cluster distribution list inside a HashTable */
static void cluster_dist_free_ht(zval *p) {
clusterDistList *dl = *(clusterDistList**)p;
int i;
for (i = 0; i < dl->len; i++) {
if (dl->entry[i].key_free)
efree(dl->entry[i].key);
if (dl->entry[i].val_free)
efree(dl->entry[i].val);
}
efree(dl->entry);
efree(dl);
}
/* Spin up a HashTable that will contain distribution lists */
HashTable *cluster_dist_create(void) {
HashTable *ret;
ALLOC_HASHTABLE(ret);
zend_hash_init(ret, 0, NULL, cluster_dist_free_ht, 0);
return ret;
}
/* Free distribution list */
void cluster_dist_free(HashTable *ht) {
zend_hash_destroy(ht);
efree(ht);
}
/* Create a clusterDistList object */
static clusterDistList *cluster_dl_create(void) {
clusterDistList *dl;
dl = emalloc(sizeof(clusterDistList));
dl->entry = emalloc(CLUSTER_KEYDIST_ALLOC * sizeof(clusterKeyVal));
dl->size = CLUSTER_KEYDIST_ALLOC;
dl->len = 0;
return dl;
}
/* Add a key to a dist list, returning the keval entry */
static clusterKeyVal *cluster_dl_add_key(clusterDistList *dl, char *key,
int key_len, int key_free)
{
// Reallocate if required
if (dl->len == dl->size) {
dl->entry = erealloc(dl->entry, sizeof(clusterKeyVal) * dl->size * 2);
dl->size *= 2;
}
// Set key info
dl->entry[dl->len].key = key;
dl->entry[dl->len].key_len = key_len;
dl->entry[dl->len].key_free = key_free;
// NULL out any values
dl->entry[dl->len].val = NULL;
dl->entry[dl->len].val_len = 0;
dl->entry[dl->len].val_free = 0;
return &(dl->entry[dl->len++]);
}
/* Add a key, returning a pointer to the entry where passed for easy adding
* of values to match this key */
int cluster_dist_add_key(redisCluster *c, HashTable *ht, char *key,
size_t key_len, clusterKeyVal **kv)
{
int key_free;
short slot;
clusterDistList *dl;
clusterKeyVal *retptr;
// Prefix our key and hash it
key_free = redis_key_prefix(c->flags, &key, &key_len);
slot = cluster_hash_key(key, key_len);
// We can't do this if we don't fully understand the keyspace
if (c->master[slot] == NULL) {
if (key_free) efree(key);
return FAILURE;
}
// Look for this slot
if ((dl = zend_hash_index_find_ptr(ht, (zend_ulong)slot)) == NULL) {
dl = cluster_dl_create();
zend_hash_index_update_ptr(ht, (zend_ulong)slot, dl);
}
// Now actually add this key
retptr = cluster_dl_add_key(dl, key, key_len, key_free);
// Push our return pointer if requested
if (kv) *kv = retptr;
return SUCCESS;
}
/* Provided a clusterKeyVal, add a value */
void cluster_dist_add_val(redisCluster *c, clusterKeyVal *kv, zval *z_val
)
{
char *val;
size_t val_len;
int val_free;
// Serialize our value
val_free = redis_pack(c->flags, z_val, &val, &val_len);
// Attach it to the provied keyval entry
kv->val = val;
kv->val_len = val_len;
kv->val_free = val_free;
}
/* Free allocated memory for a clusterMultiCmd */
void cluster_multi_free(clusterMultiCmd *mc) {
efree(mc->cmd.c);
efree(mc->args.c);
}
/* Add an argument to a clusterMultiCmd */
void cluster_multi_add(clusterMultiCmd *mc, char *data, int data_len) {
mc->argc++;
redis_cmd_append_sstr(&(mc->args), data, data_len);
}
/* Finalize a clusterMutliCmd by constructing the whole thing */
void cluster_multi_fini(clusterMultiCmd *mc) {
mc->cmd.len = 0;
redis_cmd_init_sstr(&(mc->cmd), mc->argc, mc->kw, mc->kw_len);
smart_string_appendl(&(mc->cmd), mc->args.c, mc->args.len);
}
/* Set our last error string encountered */
static void
cluster_set_err(redisCluster *c, char *err, int err_len)
{
// Free our last error
if (c->err != NULL) {
zend_string_release(c->err);
c->err = NULL;
}
if (err != NULL && err_len > 0) {
c->err = zend_string_init(err, err_len, 0);
if (err_len >= sizeof("CLUSTERDOWN") - 1 &&
!memcmp(err, "CLUSTERDOWN", sizeof("CLUSTERDOWN") - 1)
) {
c->clusterdown = 1;
}
}
}
/* Destructor for slaves */
static void ht_free_slave(zval *data) {
if (*(redisClusterNode**)data) {
cluster_free_node(*(redisClusterNode**)data);
}
}
/* Get the hash slot for a given key */
unsigned short cluster_hash_key(const char *key, int len) {
int s, e;
// Find first occurrence of {, if any
for (s = 0; s < len; s++) {
if (key[s]=='{') break;
}
// There is no '{', hash everything
if (s == len) return crc16(key, len) & REDIS_CLUSTER_MOD;
// Found it, look for a tailing '}'
for (e =s + 1; e < len; e++) {
if (key[e] == '}') break;
}
// Hash the whole key if we don't find a tailing } or if {} is empty
if (e == len || e == s+1) return crc16(key, len) & REDIS_CLUSTER_MOD;
// Hash just the bit between { and }
return crc16((char*)key+s+1,e-s-1) & REDIS_CLUSTER_MOD;
}
unsigned short cluster_hash_key_zstr(zend_string *key) {
return cluster_hash_key(ZSTR_VAL(key), ZSTR_LEN(key));
}
/* Grab the current time in milliseconds */
long long mstime(void) {
struct timeval tv;
long long mst;
gettimeofday(&tv, NULL);
mst = ((long long)tv.tv_sec)*1000;
mst += tv.tv_usec/1000;
return mst;
}
/* Hash a key from a ZVAL */
unsigned short cluster_hash_key_zval(zval *z_key) {
const char *kptr;
char buf[255];
int klen;
// Switch based on ZVAL type
switch(Z_TYPE_P(z_key)) {
case IS_STRING:
kptr = Z_STRVAL_P(z_key);
klen = Z_STRLEN_P(z_key);
break;
case IS_LONG:
klen = snprintf(buf,sizeof(buf),ZEND_LONG_FMT,Z_LVAL_P(z_key));
kptr = (const char *)buf;
break;
case IS_DOUBLE:
klen = snprintf(buf,sizeof(buf),"%f",Z_DVAL_P(z_key));
kptr = (const char *)buf;
break;
case IS_ARRAY:
kptr = "Array";
klen = sizeof("Array")-1;
break;
case IS_OBJECT:
kptr = "Object";
klen = sizeof("Object")-1;
break;
default:
kptr = "";
klen = 0;
}
// Hash the string representation
return cluster_hash_key(kptr, klen);
}
/* Fisher-Yates shuffle for integer array */
static void fyshuffle(int *array, size_t len) {
int temp, n = len;
size_t r;
/* Randomize */
while (n > 1) {
r = ((int)((double)n-- * (rand() / (RAND_MAX+1.0))));
temp = array[n];
array[n] = array[r];
array[r] = temp;
};
}
/* Execute a CLUSTER SLOTS command against the seed socket, and return the
* reply or NULL on failure. */
clusterReply* cluster_get_slots(RedisSock *redis_sock)
{
clusterReply *r;
REDIS_REPLY_TYPE type;
long len;
// Send the command to the socket and consume reply type
if (redis_sock_write(redis_sock, RESP_CLUSTER_SLOTS_CMD,
sizeof(RESP_CLUSTER_SLOTS_CMD)-1) < 0 ||
redis_read_reply_type(redis_sock, &type, &len) < 0)
{
return NULL;
}
// Consume the rest of our response
if ((r = cluster_read_sock_resp(redis_sock, type, NULL, len)) == NULL ||
r->type != TYPE_MULTIBULK || r->elements < 1)
{
if (r) cluster_free_reply(r, 1);
return NULL;
}
// Return our reply
return r;
}
/* Create a cluster node */
static redisClusterNode*
cluster_node_create(redisCluster *c, char *host, size_t host_len,
unsigned short port, unsigned short slot, short slave)
{
redisClusterNode *node = emalloc(sizeof(redisClusterNode));
// It lives in at least this slot, flag slave status
node->slot = slot;
node->slave = slave;
node->slaves = NULL;
/* Initialize our list of slot ranges */
zend_llist_init(&node->slots, sizeof(redisSlotRange), NULL, 0);
// Attach socket
node->sock = redis_sock_create(host, host_len, port,
c->flags->timeout, c->flags->read_timeout,
c->flags->persistent, NULL, 0);
/* Stream context */
node->sock->stream_ctx = c->flags->stream_ctx;
redis_sock_set_auth(node->sock, c->flags->user, c->flags->pass);
return node;
}
/* Attach a slave to a master */
PHP_REDIS_API int
cluster_node_add_slave(redisClusterNode *master, redisClusterNode *slave)
{
zend_ulong index;
// Allocate our slaves hash table if we haven't yet
if (!master->slaves) {
ALLOC_HASHTABLE(master->slaves);
zend_hash_init(master->slaves, 0, NULL, ht_free_slave, 0);
index = 1;
} else {
index = master->slaves->nNextFreeElement;
}
return zend_hash_index_update_ptr(master->slaves, index, slave) != NULL;
}
/* Sanity check/validation for CLUSTER SLOTS command */
#define VALIDATE_SLOTS_OUTER(r) \
(r->elements >= 3 && r2->element[0]->type == TYPE_INT && \
r->element[1]->type == TYPE_INT)
#define VALIDATE_SLOTS_INNER(r) \
(r->type == TYPE_MULTIBULK && r->elements >= 2 && \
r->element[0]->type == TYPE_BULK && r->element[1]->type == TYPE_INT)
/* Use the output of CLUSTER SLOTS to map our nodes */
static int cluster_map_slots(redisCluster *c, clusterReply *r) {
redisClusterNode *pnode, *master, *slave;
redisSlotRange range;
int i,j, hlen, klen;
short low, high;
clusterReply *r2, *r3;
unsigned short port;
char *host, key[1024];
zend_hash_clean(c->nodes);
for (i = 0; i < r->elements; i++) {
// Inner response
r2 = r->element[i];
// Validate outer and master slot
if (!VALIDATE_SLOTS_OUTER(r2) || !VALIDATE_SLOTS_INNER(r2->element[2])) {
return -1;
}
// Master
r3 = r2->element[2];
// Grab our slot range, as well as master host/port
low = (unsigned short)r2->element[0]->integer;
high = (unsigned short)r2->element[1]->integer;
host = r3->element[0]->str;
hlen = r3->element[0]->len;
port = (unsigned short)r3->element[1]->integer;
// If the node is new, create and add to nodes. Otherwise use it.
klen = snprintf(key, sizeof(key), "%s:%d", host, port);
if ((pnode = zend_hash_str_find_ptr(c->nodes, key, klen)) == NULL) {
master = cluster_node_create(c, host, hlen, port, low, 0);
zend_hash_str_update_ptr(c->nodes, key, klen, master);
// Attach slaves first time we encounter a given master in order to avoid regitering the slaves multiple times
for (j = 3; j< r2->elements; j++) {
r3 = r2->element[j];
if (!VALIDATE_SLOTS_INNER(r3)) {
return -1;
}
// Skip slaves where the host is ""
if (r3->element[0]->len == 0) continue;
// Attach this node to our slave
slave = cluster_node_create(c, r3->element[0]->str,
(int)r3->element[0]->len,
(unsigned short)r3->element[1]->integer, low, 1);
cluster_node_add_slave(master, slave);
}
} else {
master = pnode;
}
// Attach this node to each slot in the range
for (j = low; j<= high; j++) {
c->master[j] = master;
}
/* Append to our list of slot ranges */
range.low = low; range.high = high;
zend_llist_add_element(&master->slots, &range);
}
// Success
return 0;
}
/* Free a redisClusterNode structure */
PHP_REDIS_API void cluster_free_node(redisClusterNode *node) {
if (node->slaves) {
zend_hash_destroy(node->slaves);
efree(node->slaves);
}
zend_llist_destroy(&node->slots);
redis_free_socket(node->sock);
efree(node);
}
/* Get or create a redisClusterNode that corresponds to the asking redirection */
static redisClusterNode *cluster_get_asking_node(redisCluster *c) {
redisClusterNode *pNode;
char key[1024];
int key_len;
/* Hashed by host:port */
key_len = snprintf(key, sizeof(key), "%s:%u", c->redir_host, c->redir_port);
/* See if we've already attached to it */
if ((pNode = zend_hash_str_find_ptr(c->nodes, key, key_len)) != NULL) {
return pNode;
}
/* This host:port is unknown to us, so add it */
pNode = cluster_node_create(c, c->redir_host, c->redir_host_len,
c->redir_port, c->redir_slot, 0);
/* Return the node */
return pNode;
}
/* Get or create a node at the host:port we were asked to check, and return the
* redis_sock for it. */
static RedisSock *cluster_get_asking_sock(redisCluster *c) {
return cluster_get_asking_node(c)->sock;
}
/* Our context seeds will be a hash table with RedisSock* pointers */
static void ht_free_seed(zval *data) {
RedisSock *redis_sock = *(RedisSock**)data;
if (redis_sock) redis_free_socket(redis_sock);
}
/* Free redisClusterNode objects we've stored */
static void ht_free_node(zval *data) {
redisClusterNode *node = *(redisClusterNode**)data;
cluster_free_node(node);
}
/* zend_llist of slot ranges -> persistent array */
static redisSlotRange *slot_range_list_clone(zend_llist *src, size_t *count) {
redisSlotRange *dst, *range;
size_t i = 0;
*count = zend_llist_count(src);
dst = pemalloc(*count * sizeof(*dst), 1);
range = zend_llist_get_first(src);
while (range) {
memcpy(&dst[i++], range, sizeof(*range));
range = zend_llist_get_next(src);
}
return dst;
}
/* Construct a redisCluster object */
PHP_REDIS_API redisCluster *cluster_create(double timeout, double read_timeout,
int failover, int persistent)
{
redisCluster *c;
/* Actual our actual cluster structure */
c = ecalloc(1, sizeof(redisCluster));
/* Initialize flags and settings */
c->flags = ecalloc(1, sizeof(RedisSock));
c->flags->timeout = timeout;
c->flags->read_timeout = read_timeout;
c->flags->persistent = persistent;
c->subscribed_slot = -1;
c->clusterdown = 0;
c->failover = failover;
c->err = NULL;
/* Set up our waitms based on timeout */
c->waitms = (long)(1000 * timeout);
/* Allocate our seeds hash table */
ALLOC_HASHTABLE(c->seeds);
zend_hash_init(c->seeds, 0, NULL, ht_free_seed, 0);
/* Allocate our nodes HashTable */
ALLOC_HASHTABLE(c->nodes);
zend_hash_init(c->nodes, 0, NULL, ht_free_node, 0);
return c;
}
PHP_REDIS_API void
cluster_free(redisCluster *c, int free_ctx)
{
/* Disconnect from each node we're connected to */
cluster_disconnect(c, 0);
/* Free any allocated prefix */
if (c->flags->prefix) zend_string_release(c->flags->prefix);
redis_sock_free_auth(c->flags);
efree(c->flags);
/* Call hash table destructors */
zend_hash_destroy(c->seeds);
zend_hash_destroy(c->nodes);
/* Free hash tables themselves */
efree(c->seeds);
efree(c->nodes);
/* Free any error we've got */
if (c->err) zend_string_release(c->err);
if (c->cache_key) {
/* Invalidate persistent cache if the cluster has changed */
if (c->redirections) {
zend_hash_del(&EG(persistent_list), c->cache_key);
}
/* Release our hold on the cache key */
zend_string_release(c->cache_key);
}
/* Free structure itself */
if (free_ctx) efree(c);
}
/* Create a cluster slot cache structure */
PHP_REDIS_API
redisCachedCluster *cluster_cache_create(zend_string *hash, HashTable *nodes) {
redisCachedCluster *cc;
redisCachedMaster *cm;
redisClusterNode *node, *slave;
cc = pecalloc(1, sizeof(*cc), 1);
cc->hash = zend_string_dup(hash, 1);
/* Copy nodes */
cc->master = pecalloc(zend_hash_num_elements(nodes), sizeof(*cc->master), 1);
ZEND_HASH_FOREACH_PTR(nodes, node) {
/* Skip slaves */
if (node->slave) continue;
cm = &cc->master[cc->count];
/* Duplicate host/port and clone slot ranges */
cm->host.addr = zend_string_dup(node->sock->host, 1);
cm->host.port = node->sock->port;
/* Copy over slot ranges */
cm->slot = slot_range_list_clone(&node->slots, &cm->slots);
/* Attach any slave nodes we have. */
if (node->slaves) {
/* Allocate memory for slaves */
cm->slave = pecalloc(zend_hash_num_elements(node->slaves), sizeof(*cm->slave), 1);
/* Copy host/port information for each slave */
ZEND_HASH_FOREACH_PTR(node->slaves, slave) {
cm->slave[cm->slaves].addr = zend_string_dup(slave->sock->host, 1);
cm->slave[cm->slaves].port = slave->sock->port;
cm->slaves++;
} ZEND_HASH_FOREACH_END();
}
cc->count++;
} ZEND_HASH_FOREACH_END();
return cc;
}
static void cluster_free_cached_master(redisCachedMaster *cm) {
size_t i;
/* Free each slave entry */
for (i = 0; i < cm->slaves; i++) {
zend_string_release(cm->slave[i].addr);
}
/* Free other elements */
zend_string_release(cm->host.addr);
pefree(cm->slave, 1);
pefree(cm->slot, 1);
}
static redisClusterNode*
cached_master_clone(redisCluster *c, redisCachedMaster *cm) {
redisClusterNode *node;
size_t i;
node = cluster_node_create(c, ZSTR_VAL(cm->host.addr), ZSTR_LEN(cm->host.addr),
cm->host.port, cm->slot[0].low, 0);
/* Now copy in our slot ranges */
for (i = 0; i < cm->slots; i++) {
zend_llist_add_element(&node->slots, &cm->slot[i]);
}
return node;
}
/* Destroy a persistent cached cluster */
PHP_REDIS_API void cluster_cache_free(redisCachedCluster *rcc) {
size_t i;
/* Free masters */
for (i = 0; i < rcc->count; i++) {
cluster_free_cached_master(&rcc->master[i]);
}
zend_string_release(rcc->hash);
pefree(rcc->master, 1);
pefree(rcc, 1);
}
/* Initialize cluster from cached slots */
PHP_REDIS_API
void cluster_init_cache(redisCluster *c, redisCachedCluster *cc) {
RedisSock *sock;
redisClusterNode *mnode, *slave;
redisCachedMaster *cm;
char key[HOST_NAME_MAX];
size_t keylen, i, j, s;
int *map;
/* Randomize seeds */
map = emalloc(sizeof(*map) * cc->count);
for (i = 0; i < cc->count; i++) map[i] = i;
fyshuffle(map, cc->count);
/* Duplicate the hash key so we can invalidate when redirected */
c->cache_key = zend_string_copy(cc->hash);
/* Iterate over masters */
for (i = 0; i < cc->count; i++) {
/* Grab the next master */
cm = &cc->master[map[i]];
/* Hash our host and port */
keylen = snprintf(key, sizeof(key), "%s:%u", ZSTR_VAL(cm->host.addr), cm->host.port);
/* Create socket */
sock = redis_sock_create(ZSTR_VAL(cm->host.addr), ZSTR_LEN(cm->host.addr), cm->host.port,
c->flags->timeout, c->flags->read_timeout, c->flags->persistent,
NULL, 0);
/* Stream context */
sock->stream_ctx = c->flags->stream_ctx;
/* Add to seed nodes */
zend_hash_str_update_ptr(c->seeds, key, keylen, sock);
/* Create master node */
mnode = cached_master_clone(c, cm);
/* Add our master */
zend_hash_str_update_ptr(c->nodes, key, keylen, mnode);
/* Attach any slaves */
for (s = 0; s < cm->slaves; s++) {
zend_string *host = cm->slave[s].addr;
slave = cluster_node_create(c, ZSTR_VAL(host), ZSTR_LEN(host), cm->slave[s].port, 0, 1);
cluster_node_add_slave(mnode, slave);
}
/* Hook up direct slot access */
for (j = 0; j < cm->slots; j++) {
for (s = cm->slot[j].low; s <= cm->slot[j].high; s++) {
c->master[s] = mnode;
}
}
}
efree(map);
}
/* Initialize seeds. By the time we get here we've already validated our
* seeds array and know we have a non-empty array of strings all in
* host:port format. */
PHP_REDIS_API void
cluster_init_seeds(redisCluster *c, zend_string **seeds, uint32_t nseeds)
{
RedisSock *sock;
char *seed, *sep, key[1024];
int key_len, i, *map;
/* Get a randomized order to hit our seeds */
map = ecalloc(nseeds, sizeof(*map));
for (i = 0; i < nseeds; i++) map[i] = i;
fyshuffle(map, nseeds);
for (i = 0; i < nseeds; i++) {
seed = ZSTR_VAL(seeds[map[i]]);
sep = strrchr(seed, ':');
ZEND_ASSERT(sep != NULL);
// Allocate a structure for this seed
sock = redis_sock_create(seed, sep - seed, atoi(sep + 1),
c->flags->timeout, c->flags->read_timeout,
c->flags->persistent, NULL, 0);
/* Stream context */
sock->stream_ctx = c->flags->stream_ctx;
/* Credentials */
redis_sock_set_auth(sock, c->flags->user, c->flags->pass);
// Index this seed by host/port
key_len = snprintf(key, sizeof(key), "%s:%u", ZSTR_VAL(sock->host),
sock->port);
// Add to our seed HashTable
zend_hash_str_update_ptr(c->seeds, key, key_len, sock);
}
efree(map);
}
/* Initial mapping of our cluster keyspace */
PHP_REDIS_API int cluster_map_keyspace(redisCluster *c) {
RedisSock *seed;
clusterReply *slots = NULL;
int mapped = 0;
// Iterate over seeds until we can get slots
ZEND_HASH_FOREACH_PTR(c->seeds, seed) {
// Attempt to connect to this seed node
if (seed == NULL || redis_sock_server_open(seed) != SUCCESS) {
continue;
}
// Parse out cluster nodes. Flag mapped if we are valid
slots = cluster_get_slots(seed);
if (slots) {
mapped = !cluster_map_slots(c, slots);
// Bin anything mapped, if we failed somewhere
if (!mapped) {
memset(c->master, 0, sizeof(redisClusterNode*)*REDIS_CLUSTER_SLOTS);
}
}
redis_sock_disconnect(seed, 0, 1);
if (mapped) break;
} ZEND_HASH_FOREACH_END();
// Clean up slots reply if we got one
if (slots) cluster_free_reply(slots, 1);
// Throw an exception if we couldn't map
if (!mapped) {
CLUSTER_THROW_EXCEPTION("Couldn't map cluster keyspace using any provided seed", 0);
return FAILURE;
}
return SUCCESS;
}
/* Parse the MOVED OR ASK redirection payload when we get such a response
* and apply this information to our cluster. If we encounter a parse error
* nothing in the cluster will be modified, and -1 is returned. */
static int cluster_set_redirection(redisCluster* c, char *msg, int moved)
{
char *host, *port;
/* The Redis Cluster specification suggests clients do not update
* their slot mapping for an ASK redirection, only for MOVED */
if (moved) c->redirections++;
/* Move past "MOVED" or "ASK */
msg += moved ? MOVED_LEN : ASK_LEN;
/* Make sure we can find host */
if ((host = strchr(msg, ' ')) == NULL) return -1;
*host++ = '\0';
/* Find port, searching right to left in case of IPv6 */
if ((port = strrchr(host, ':')) == NULL) return -1;
*port++ = '\0';
// Success, apply it
c->redir_type = moved ? REDIR_MOVED : REDIR_ASK;
strncpy(c->redir_host, host, sizeof(c->redir_host) - 1);
c->redir_host_len = port - host - 1;
c->redir_slot = (unsigned short)atoi(msg);
c->redir_port = (unsigned short)atoi(port);
return 0;
}
/* Once we write a command to a node in our cluster, this function will check
* the reply type and extract information from those that will specify a length
* bit. If we encounter an error condition, we'll check for MOVED or ASK
* redirection, parsing out slot host and port so the caller can take
* appropriate action.
*
* In the case of a non MOVED/ASK error, we wlll set our cluster error
* condition so GetLastError can be queried by the client.
*
* This function will return -1 on a critical error (e.g. parse/communication
* error, 0 if no redirection was encountered, and 1 if the data was moved. */
static int cluster_check_response(redisCluster *c, REDIS_REPLY_TYPE *reply_type)
{
size_t sz;
// Clear out any prior error state and our last line response
CLUSTER_CLEAR_ERROR(c);
CLUSTER_CLEAR_REPLY(c);
if (-1 == redis_check_eof(c->cmd_sock, 1, 1) ||
EOF == (*reply_type = redis_sock_getc(c->cmd_sock)))
{
return -1;
}
// In the event of an ERROR, check if it's a MOVED/ASK error
if (*reply_type == TYPE_ERR) {
char inbuf[4096];
size_t nbytes;
int moved;
// Attempt to read the error
if (!redis_sock_get_line(c->cmd_sock, inbuf, sizeof(inbuf), &nbytes)) {
return -1;
}
// Check for MOVED or ASK redirection
if ((moved = IS_MOVED(inbuf)) || IS_ASK(inbuf)) {
/* Make sure we can parse the redirection host and port */
return !cluster_set_redirection(c, inbuf, moved) ? 1 : -1;
}
// Capture the error string Redis returned
cluster_set_err(c, inbuf, strlen(inbuf)-2);
return 0;
}
// Fetch the first line of our response from Redis.
if (redis_sock_gets(c->cmd_sock,c->line_reply,sizeof(c->line_reply),
&sz) < 0)
{
return -1;
}
// For replies that will give us a numeric length, convert it
if (*reply_type != TYPE_LINE) {
c->reply_len = strtol(c->line_reply, NULL, 10);
} else {
c->reply_len = (long long)sz;
}
// Clear out any previous error, and return that the data is here
CLUSTER_CLEAR_ERROR(c);
return 0;
}
/* Disconnect from each node we're connected to */
PHP_REDIS_API void cluster_disconnect(redisCluster *c, int force) {
redisClusterNode *node, *slave;
ZEND_HASH_FOREACH_PTR(c->nodes, node) {
if (node == NULL) continue;
/* Disconnect from the master */
redis_sock_disconnect(node->sock, force, 1);
/* We also want to disconnect any slave connections so they will be pooled
* in the event we are using persistent connections and connection pooling. */
if (node->slaves) {
ZEND_HASH_FOREACH_PTR(node->slaves, slave) {
redis_sock_disconnect(slave->sock, force, 1);
} ZEND_HASH_FOREACH_END();
}
} ZEND_HASH_FOREACH_END();
}
/* This method attempts to write our command at random to the master and any
* attached slaves, until we either successufly do so, or fail. */
static int cluster_dist_write(redisCluster *c, const char *cmd, size_t sz,
int nomaster)
{
int i, count = 1, *nodes;
RedisSock *redis_sock;
/* Determine our overall node count */
if (c->master[c->cmd_slot]->slaves) {
count += zend_hash_num_elements(c->master[c->cmd_slot]->slaves);
}
/* Allocate memory for master + slaves or just slaves */
nodes = emalloc(sizeof(int)*count);
/* Populate our array with the master and each of it's slaves, then
* randomize them, so we will pick from the master or some slave. */
for (i = 0; i < count; i++) nodes[i] = i;
fyshuffle(nodes, count);
/* Iterate through our nodes until we find one we can write to or fail */
for (i = 0; i < count; i++) {
/* Skip if this is the master node and we don't want to query that */
if (nomaster && nodes[i] == 0)
continue;
/* Get the slave for this index */
redis_sock = cluster_slot_sock(c, c->cmd_slot, nodes[i]);
if (!redis_sock) continue;
/* If we're not on the master, attempt to send the READONLY command to
* this slave, and skip it if that fails */
if (nodes[i] == 0 || cluster_send_readonly(redis_sock) == 0) {
/* Attempt to send the command */
if (CLUSTER_SEND_PAYLOAD(redis_sock, cmd, sz)) {
c->cmd_sock = redis_sock;
efree(nodes);
return 0;
}
}
}
/* Clean up our shuffled array */
efree(nodes);
/* Couldn't send to the master or any slave */
return -1;
}
/* Attempt to write our command to the current c->cmd_sock socket. For write
* commands, we attempt to query the master for this slot, and in the event of
* a failure, try to query every remaining node for a redirection.
*
* If we're issuing a readonly command, we use one of three strategies, depending
* on our redisCluster->failover setting.
*
* REDIS_FAILOVER_NONE:
* The command is treated just like a write command, and will only be executed
* against the known master for this slot.
* REDIS_FAILOVER_ERROR:
* If we're unable to communicate with this slot's master, we attempt the query
* against any slaves (at random) that this master has.
* REDIS_FAILOVER_DISTRIBUTE:
* We pick at random from the master and any slaves it has. This option will
* load balance between masters and slaves
* REDIS_FAILOVER_DISTRIBUTE_SLAVES:
* We pick at random from slave nodes of a given master. This option is
* used to load balance read queries against N slaves.
*
* Once we are able to find a node we can write to, we check for MOVED or
* ASKING redirection, such that the keyspace can be updated.
*/
static int cluster_sock_write(redisCluster *c, const char *cmd, size_t sz,
int direct)
{
redisClusterNode *seed_node;
RedisSock *redis_sock;
int failover, nomaster;
/* First try the socket requested */
redis_sock = c->cmd_sock;
/* Readonly is irrelevant if we're not configured to failover */
failover = c->readonly && c->failover != REDIS_FAILOVER_NONE ?
c->failover : REDIS_FAILOVER_NONE;
/* If in ASK redirection, get/create the node for that host:port, otherwise
* just use the command socket. */
if (c->redir_type == REDIR_ASK) {
if (cluster_send_asking(c->cmd_sock) < 0) {
return -1;
}
}
/* Attempt to send our command payload to the cluster. If we're not set up
* to failover, just try the master. If we're configured to failover on
* error, try the master and then fall back to any slaves. When we're set
* up to distribute the commands, try to write to any node on this slot
* at random. */
if (failover == REDIS_FAILOVER_NONE) {
/* Success if we can send our payload to the master */
if (CLUSTER_SEND_PAYLOAD(redis_sock, cmd, sz)) return 0;
} else if (failover == REDIS_FAILOVER_ERROR) {
/* Try the master, then fall back to any slaves we may have */
if (CLUSTER_SEND_PAYLOAD(redis_sock, cmd, sz) ||
!cluster_dist_write(c, cmd, sz, 1)) return 0;
} else {
/* Include or exclude master node depending on failover option and
* attempt to make our write */
nomaster = failover == REDIS_FAILOVER_DISTRIBUTE_SLAVES;
if (!cluster_dist_write(c, cmd, sz, nomaster)) {
/* We were able to write to a master or slave at random */
return 0;
}
}
/* Don't fall back if direct communication with this slot is required. */
if (direct) return -1;
/* Fall back by attempting the request against every known node */
ZEND_HASH_FOREACH_PTR(c->nodes, seed_node) {
/* Skip this node if it's the one that failed, or if it's a slave */
if (seed_node == NULL || seed_node->sock == redis_sock || seed_node->slave) continue;
/* Connect to this node if we haven't already and attempt to write our request to this node */
if (CLUSTER_SEND_PAYLOAD(seed_node->sock, cmd, sz)) {
c->cmd_slot = seed_node->slot;
c->cmd_sock = seed_node->sock;
return 0;
}
} ZEND_HASH_FOREACH_END();
/* We were unable to write to any node in our cluster */
return -1;
}
/* Helper to find if we've got a host:port mapped in our cluster nodes. */
static redisClusterNode *cluster_find_node(redisCluster *c, const char *host,
unsigned short port)
{
int key_len;
char key[1024];
key_len = snprintf(key,sizeof(key),"%s:%d", host, port);
return zend_hash_str_find_ptr(c->nodes, key, key_len);
}
/* Provided a redisCluster object, the slot where we thought data was and
* the slot where data was moved, update our node mapping */
static void cluster_update_slot(redisCluster *c) {
redisClusterNode *node;
char key[1024];
size_t klen;
/* Do we already have the new slot mapped */
if (c->master[c->redir_slot]) {
/* No need to do anything if it's the same node */
if (!CLUSTER_REDIR_CMP(c, SLOT_SOCK(c,c->redir_slot))) {
return;
}
/* Check to see if we have this new node mapped */
node = cluster_find_node(c, c->redir_host, c->redir_port);
if (node) {
/* Just point to this slot */
c->master[c->redir_slot] = node;
} else {
/* If the redirected node is a replica of the previous slot owner, a failover has taken place.
We must then remap the cluster's keyspace in order to update the cluster's topology. */
redisClusterNode *prev_master = SLOT(c,c->redir_slot);
redisClusterNode *slave;
ZEND_HASH_FOREACH_PTR(prev_master->slaves, slave) {
if (slave == NULL) {
continue;
}
if (!CLUSTER_REDIR_CMP(c, slave->sock)) {
// Detected a failover, the redirected node was a replica
// Remap the cluster's keyspace
cluster_map_keyspace(c);
return;
}
} ZEND_HASH_FOREACH_END();
/* Create our node */
node = cluster_node_create(c, c->redir_host, c->redir_host_len,
c->redir_port, c->redir_slot, 0);
/* Our node is new, so keep track of it for cleanup */
klen = snprintf(key, sizeof(key), "%s:%d", c->redir_host, c->redir_port);
zend_hash_str_update_ptr(c->nodes, key, klen, node);
/* Now point our slot at the node */
c->master[c->redir_slot] = node;
}
} else {
/* Check to see if the ip and port are mapped */
node = cluster_find_node(c, c->redir_host, c->redir_port);
if (!node) {
node = cluster_node_create(c, c->redir_host, c->redir_host_len,
c->redir_port, c->redir_slot, 0);
}
/* Map the slot to this node */
c->master[c->redir_slot] = node;
}
/* Update slot inside of node, so it can be found for command sending */
node->slot = c->redir_slot;
/* Make sure we unflag this node as a slave, as Redis Cluster will only ever
* direct us to master nodes. */
node->slave = 0;
}
/* Abort any transaction in process, by sending DISCARD to any nodes that
* have active transactions in progress. If we can't send DISCARD, we need
* to disconnect as it would leave us in an undefined state. */
PHP_REDIS_API int cluster_abort_exec(redisCluster *c) {
clusterFoldItem *fi = c->multi_head;
/* Loop through our fold items */
while (fi) {
if (SLOT_SOCK(c,fi->slot)->mode == MULTI) {
if (cluster_send_discard(c, fi->slot) < 0) {
cluster_disconnect(c, 0);
return -1;
}
SLOT_SOCK(c,fi->slot)->mode = ATOMIC;
SLOT_SOCK(c,fi->slot)->watching = 0;
}
fi = fi->next;
}
/* Update our overall cluster state */
c->flags->mode = ATOMIC;
/* Success */
return 0;
}
/* Iterate through our slots, looking for the host/port in question. This
* should perform well enough as in almost all situations, a few or a few
* dozen servers will map all the slots */
PHP_REDIS_API short cluster_find_slot(redisCluster *c, const char *host,
unsigned short port)
{
int i;
for (i = 0; i < REDIS_CLUSTER_SLOTS; i++) {
if (c->master[i] && c->master[i]->sock &&
c->master[i]->sock->port == port &&
!strcasecmp(ZSTR_VAL(c->master[i]->sock->host), host))
{
return i;
}
}
// We didn't find it
return -1;
}
/* Send a command to a specific slot */
PHP_REDIS_API int cluster_send_slot(redisCluster *c, short slot, char *cmd,
int cmd_len, REDIS_REPLY_TYPE rtype)
{
/* Point our cluster to this slot and it's socket */
c->cmd_slot = slot;
c->cmd_sock = SLOT_SOCK(c, slot);
/* Enable multi mode on this slot if we've been directed to but haven't
* send it to this node yet */
if (c->flags->mode == MULTI && c->cmd_sock->mode != MULTI) {
if (cluster_send_multi(c, slot) == -1) {
CLUSTER_THROW_EXCEPTION("Unable to enter MULTI mode on requested slot", 0);
return -1;
}
}
/* Try the slot */
if (cluster_sock_write(c, cmd, cmd_len, 1) == -1) {
return -1;
}
c->flags->txBytes += cmd_len;
/* Check our response */
if (cluster_check_response(c, &c->reply_type) != 0 ||
(rtype != TYPE_EOF && rtype != c->reply_type)) return -1;
/* Success */
return 0;
}
/* Send a command to given slot in our cluster. If we get a MOVED or ASK error
* we attempt to send the command to the node as directed. */
PHP_REDIS_API short cluster_send_command(redisCluster *c, short slot, const char *cmd,
int cmd_len)
{
int resp, timedout = 0;
long msstart;
if (!SLOT(c, slot)) {
zend_throw_exception_ex(redis_cluster_exception_ce, 0,
"The slot %d is not covered by any node in this cluster", slot);
return -1;
}
/* Set the slot we're operating against as well as it's socket. These can
* change during our request loop if we have a master failure and are
* configured to fall back to slave nodes, or if we have to fall back to
* a different slot due to no nodes serving this slot being reachable. */
c->cmd_slot = slot;
c->cmd_sock = SLOT_SOCK(c, slot);
/* Get the current time in milliseconds to handle any timeout */
msstart = mstime();
/* Our main cluster request/reply loop. This loop runs until we're able to
* get a valid reply from a node, hit our "request" timeout, or encounter a
* CLUSTERDOWN state from Redis Cluster. */
do {
/* Send MULTI to the socket if we're in MULTI mode but haven't yet */
if (c->flags->mode == MULTI && c->cmd_sock->mode != MULTI) {
/* We have to fail if we can't send MULTI to the node */
if (cluster_send_multi(c, slot) == -1) {
CLUSTER_THROW_EXCEPTION("Unable to enter MULTI mode on requested slot", 0);
return -1;
}
}
/* Attempt to deliver our command to the node, and that failing, to any
* node until we find one that is available. */
if (cluster_sock_write(c, cmd, cmd_len, 0) == -1) {
/* We have to abort, as no nodes are reachable */
CLUSTER_THROW_EXCEPTION("Can't communicate with any node in the cluster", 0);
return -1;
}
/* Check response and short-circuit on success or communication error */
resp = cluster_check_response(c, &c->reply_type);
if (resp <= 0) {
break;
}
/* Handle MOVED or ASKING redirection */
if (resp == 1) {
/* Abort if we're in a transaction as it will be invalid */
if (c->flags->mode == MULTI) {
CLUSTER_THROW_EXCEPTION("Can't process MULTI sequence when cluster is resharding", 0);
return -1;
}
if (c->redir_type == REDIR_MOVED) {
/* For MOVED redirection we want to update our cached mapping */
cluster_update_slot(c);
c->cmd_sock = SLOT_SOCK(c, slot);
} else if (c->redir_type == REDIR_ASK) {
/* For ASK redirection we want to redirect but not update slot mapping */
c->cmd_sock = cluster_get_asking_sock(c);
}
}
/* See if we've timed out in the command loop */
timedout = c->waitms ? mstime() - msstart >= c->waitms : 0;
} while (!c->clusterdown && !timedout);
// If we've detected the cluster is down, throw an exception
if (c->clusterdown) {
CLUSTER_THROW_EXCEPTION("The Redis Cluster is down (CLUSTERDOWN)", 0);
return -1;
} else if (timedout || resp == -1) {
// Make sure the socket is reconnected, it such that it is in a clean state
redis_sock_disconnect(c->cmd_sock, 1, 1);
if (timedout) {
CLUSTER_THROW_EXCEPTION("Timed out attempting to find data in the correct node!", 0);
} else {
CLUSTER_THROW_EXCEPTION("Error processing response from Redis node!", 0);
}
return -1;
}
/* Clear redirection flag */
c->redir_type = REDIR_NONE;
// Success, return the slot where data exists.
return 0;
}
/* RedisCluster response handlers. These methods all have the same prototype
* and set the proper return value for the calling cluster method. These
* methods will never be called in the case of a communication error when
* we try to send the request to the Cluster *or* if a non MOVED or ASK
* error is encountered, in which case our response processing macro will
* short circuit and RETURN_FALSE, as the error will have already been
* consumed. */
/* RAW bulk response handler */
PHP_REDIS_API void cluster_bulk_raw_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx)
{
char *resp;
// Make sure we can read the response
if (c->reply_type != TYPE_BULK ||
(resp = redis_sock_read_bulk_reply(c->cmd_sock, c->reply_len)) == NULL)
{
if (c->flags->mode != MULTI) {
RETURN_FALSE;
} else {
add_next_index_bool(&c->multi_resp, 0);
return;
}
}
// Return our response raw
CLUSTER_RETURN_STRING(c, resp, c->reply_len);
efree(resp);
}
PHP_REDIS_API void
cluster_single_line_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx)
{
char *p;
/* Cluster already has the reply so abort if this isn't a LINE response *or* if for
* some freaky reason we don't detect a null terminator */
if (c->reply_type != TYPE_LINE || !(p = memchr(c->line_reply,'\0',sizeof(c->line_reply)))) {
CLUSTER_RETURN_FALSE(c);
}
if (CLUSTER_IS_ATOMIC(c)) {
CLUSTER_RETURN_STRING(c, c->line_reply, p - c->line_reply);
} else {
add_next_index_stringl(&c->multi_resp, c->line_reply, p - c->line_reply);
}
}
/* BULK response handler */
PHP_REDIS_API void cluster_bulk_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx)
{
char *resp;
// Make sure we can read the response
if (c->reply_type != TYPE_BULK ||
(resp = redis_sock_read_bulk_reply(c->cmd_sock, c->reply_len)) == NULL)
{
CLUSTER_RETURN_FALSE(c);
}
if (CLUSTER_IS_ATOMIC(c)) {
if (!redis_unpack(c->flags, resp, c->reply_len, return_value)) {
CLUSTER_RETURN_STRING(c, resp, c->reply_len);
}
} else {
zval z_unpacked;
if (redis_unpack(c->flags, resp, c->reply_len, &z_unpacked)) {
add_next_index_zval(&c->multi_resp, &z_unpacked);
} else {
add_next_index_stringl(&c->multi_resp, resp, c->reply_len);
}
}
efree(resp);
}
/* Bulk response where we expect a double */
PHP_REDIS_API void cluster_dbl_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx)
{
char *resp;
double dbl;
// Make sure we can read the response
if (c->reply_type != TYPE_BULK ||
(resp = redis_sock_read_bulk_reply(c->cmd_sock, c->reply_len)) == NULL)
{
CLUSTER_RETURN_FALSE(c);
}
// Convert to double, free response
dbl = atof(resp);
efree(resp);
CLUSTER_RETURN_DOUBLE(c, dbl);
}
/* A boolean response. If we get here, we've consumed the '+' reply
* type and will now just verify we can read the OK */
PHP_REDIS_API void cluster_bool_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx)
{
// Check that we have +OK
if (c->reply_type != TYPE_LINE || c->reply_len != 2 ||
c->line_reply[0] != 'O' || c->line_reply[1] != 'K')
{
CLUSTER_RETURN_FALSE(c);
}
CLUSTER_RETURN_BOOL(c, 1);
}
/* Boolean response, specialized for PING */
PHP_REDIS_API void cluster_ping_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx)
{
if (c->reply_type != TYPE_LINE || c->reply_len != 4 ||
memcmp(c->line_reply,"PONG",sizeof("PONG")-1))
{
CLUSTER_RETURN_FALSE(c);
}
CLUSTER_RETURN_BOOL(c, 1);
}
PHP_REDIS_API void
cluster_hrandfield_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx)
{
if (ctx == NULL) {
cluster_bulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
} else if (ctx == PHPREDIS_CTX_PTR) {
cluster_mbulk_raw_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
} else if (ctx == PHPREDIS_CTX_PTR + 1) {
return cluster_mbulk_zipdbl_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
} else {
ZEND_ASSERT(!"memory corruption?");
}
}
PHP_REDIS_API void
cluster_pop_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx)
{
if (ctx == NULL) {
cluster_bulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
} else if (ctx == PHPREDIS_CTX_PTR) {
cluster_mbulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
} else {
ZEND_ASSERT(!"memory corruption?");
}
}
PHP_REDIS_API void
cluster_lpos_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx)
{
zval zret = {0};
c->cmd_sock->null_mbulk_as_null = c->flags->null_mbulk_as_null;
if (redis_read_lpos_response(&zret, c->cmd_sock, c->reply_type, c->reply_len, ctx) < 0) {
ZVAL_FALSE(&zret);
}
if (CLUSTER_IS_ATOMIC(c)) {
RETVAL_ZVAL(&zret, 0, 1);
} else {
add_next_index_zval(&c->multi_resp, &zret);
}
}
PHP_REDIS_API void
cluster_geosearch_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx) {
zval zret = {0};
c->cmd_sock->null_mbulk_as_null = c->flags->null_mbulk_as_null;
if (c->reply_type != TYPE_MULTIBULK ||
redis_read_geosearch_response(&zret, c->cmd_sock, c->reply_len, ctx != NULL) < 0)
{
ZVAL_FALSE(&zret);
}
if (CLUSTER_IS_ATOMIC(c)) {
RETVAL_ZVAL(&zret, 0, 1);
} else {
add_next_index_zval(&c->multi_resp, &zret);
}
}
PHP_REDIS_API void
cluster_zdiff_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx) {
if (ctx == NULL) {
cluster_mbulk_raw_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
} else if (ctx == PHPREDIS_CTX_PTR) {
cluster_mbulk_zipdbl_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
} else {
ZEND_ASSERT(!"memory corruption?");
}
}
PHP_REDIS_API void
cluster_zadd_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx) {
ZEND_ASSERT(ctx == NULL || ctx == PHPREDIS_CTX_PTR);
if (ctx == NULL) {
cluster_long_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
} else {
cluster_dbl_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
}
}
PHP_REDIS_API void
cluster_zrandmember_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx) {
if (ctx == NULL) {
cluster_bulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
} else if (ctx == PHPREDIS_CTX_PTR) {
cluster_mbulk_raw_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
} else if (ctx == PHPREDIS_CTX_PTR + 1) {
cluster_mbulk_zipdbl_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
} else {
ZEND_ASSERT(!"memory corruption?");
}
}
PHP_REDIS_API void
cluster_srandmember_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx) {
if (ctx == NULL) {
cluster_bulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
} else if (ctx == PHPREDIS_CTX_PTR) {
cluster_mbulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
} else {
ZEND_ASSERT(!"memory corruption?");
}
}
PHP_REDIS_API void
cluster_object_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx) {
ZEND_ASSERT(ctx == PHPREDIS_CTX_PTR || ctx == PHPREDIS_CTX_PTR + 1);
if (ctx == PHPREDIS_CTX_PTR) {
cluster_long_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
} else {
cluster_bulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
}
}
PHP_REDIS_API void
cluster_set_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx)
{
if (ctx == NULL) {
cluster_bool_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
} else {
cluster_bulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
}
}
/* 1 or 0 response, for things like SETNX */
PHP_REDIS_API void cluster_1_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx)
{
// Validate our reply type, and check for a zero
if (c->reply_type != TYPE_INT || c->reply_len == 0) {
CLUSTER_RETURN_FALSE(c);
}
CLUSTER_RETURN_BOOL(c, 1);
}
/* Generic integer response */
PHP_REDIS_API void cluster_long_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx)
{
if (c->reply_type != TYPE_INT) {
CLUSTER_RETURN_FALSE(c);
}
CLUSTER_RETURN_LONG(c, c->reply_len);
}
/* TYPE response handler */
PHP_REDIS_API void cluster_type_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx)
{
// Make sure we got the right kind of response
if (c->reply_type != TYPE_LINE) {
CLUSTER_RETURN_FALSE(c);
}
// Switch on the type
if (strncmp (c->line_reply, "string", 6) == 0) {
CLUSTER_RETURN_LONG(c, REDIS_STRING);
} else if (strncmp(c->line_reply, "set", 3) == 0) {
CLUSTER_RETURN_LONG(c, REDIS_SET);
} else if (strncmp(c->line_reply, "list", 4) == 0) {
CLUSTER_RETURN_LONG(c, REDIS_LIST);
} else if (strncmp(c->line_reply, "hash", 4) == 0) {
CLUSTER_RETURN_LONG(c, REDIS_HASH);
} else if (strncmp(c->line_reply, "zset", 4) == 0) {
CLUSTER_RETURN_LONG(c, REDIS_ZSET);
} else if (strncmp(c->line_reply, "stream", 6) == 0) {
CLUSTER_RETURN_LONG(c, REDIS_STREAM);
} else {
CLUSTER_RETURN_LONG(c, REDIS_NOT_FOUND);
}
}
/* SUBSCRIBE/PSCUBSCRIBE handler */
PHP_REDIS_API void cluster_sub_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx)
{
subscribeContext *sctx = (subscribeContext*)ctx;
zval z_tab, *z_tmp;
int pull = 0;
// Consume each MULTI BULK response (one per channel/pattern)
while (sctx->argc--) {
if (!cluster_zval_mbulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c,
pull, mbulk_resp_loop_raw, &z_tab)
) {
efree(sctx);
RETURN_FALSE;
}
if ((z_tmp = zend_hash_index_find(Z_ARRVAL(z_tab), 0)) == NULL ||
strcasecmp(Z_STRVAL_P(z_tmp), sctx->kw) != 0
) {
zval_dtor(&z_tab);
efree(sctx);
RETURN_FALSE;
}
zval_dtor(&z_tab);
pull = 1;
}
// Set up our callback pointers
zval z_ret, z_args[4];
sctx->cb.fci.retval = &z_ret;
sctx->cb.fci.params = z_args;
/* We're in a subscribe loop */
c->subscribed_slot = c->cmd_slot;
/* Multibulk response, {[pattern], type, channel, payload} */
while (1) {
/* Arguments */
zval *z_type, *z_chan, *z_pat = NULL, *z_data;
int tab_idx = 1, is_pmsg;
// Get the next subscribe response
if (!cluster_zval_mbulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, 1, mbulk_resp_loop, &z_tab) ||
(z_type = zend_hash_index_find(Z_ARRVAL(z_tab), 0)) == NULL
) {
break;
}
// Make sure we have a message or pmessage
if (!strncmp(Z_STRVAL_P(z_type), "message", 7) ||
!strncmp(Z_STRVAL_P(z_type), "pmessage", 8)
) {
is_pmsg = *Z_STRVAL_P(z_type) == 'p';
} else {
zval_dtor(&z_tab);
continue;
}
if (is_pmsg && (z_pat = zend_hash_index_find(Z_ARRVAL(z_tab), tab_idx++)) == NULL) {
break;
}
// Extract channel and data
if ((z_chan = zend_hash_index_find(Z_ARRVAL(z_tab), tab_idx++)) == NULL ||
(z_data = zend_hash_index_find(Z_ARRVAL(z_tab), tab_idx++)) == NULL
) {
break;
}
// Always pass our object through
z_args[0] = *getThis();
// Set up calbacks depending on type
if (is_pmsg) {
z_args[1] = *z_pat;
z_args[2] = *z_chan;
z_args[3] = *z_data;
} else {
z_args[1] = *z_chan;
z_args[2] = *z_data;
}
// Set arg count
sctx->cb.fci.param_count = tab_idx;
// Execute our callback
if (zend_call_function(&sctx->cb.fci, &sctx->cb.fci_cache) != SUCCESS) {
break;
}
// If we have a return value, free it
zval_ptr_dtor(&z_ret);
zval_dtor(&z_tab);
}
// We're no longer subscribing, due to an error
c->subscribed_slot = -1;
// Cleanup
zval_dtor(&z_tab);
efree(sctx);
// Failure
RETURN_FALSE;
}
/* UNSUBSCRIBE/PUNSUBSCRIBE */
PHP_REDIS_API void cluster_unsub_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx)
{
subscribeContext *sctx = (subscribeContext*)ctx;
zval z_tab, *z_chan, *z_flag;
int pull = 0, argc = sctx->argc;
efree(sctx);
array_init(return_value);
// Consume each response
while (argc--) {
// Fail if we didn't get an array or can't find index 1
if (!cluster_zval_mbulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, pull, mbulk_resp_loop_raw, &z_tab) ||
(z_chan = zend_hash_index_find(Z_ARRVAL(z_tab), 1)) == NULL
) {
zval_dtor(&z_tab);
zval_dtor(return_value);
RETURN_FALSE;
}
// Find the flag for this channel/pattern
if ((z_flag = zend_hash_index_find(Z_ARRVAL(z_tab), 2)) == NULL ||
Z_STRLEN_P(z_flag) != 2
) {
zval_dtor(&z_tab);
zval_dtor(return_value);
RETURN_FALSE;
}
// Redis will give us either :1 or :0 here
char *flag = Z_STRVAL_P(z_flag);
// Add result
add_assoc_bool(return_value, Z_STRVAL_P(z_chan), flag[1] == '1');
zval_dtor(&z_tab);
pull = 1;
}
}
/* Recursive MULTI BULK -> PHP style response handling */
static void cluster_mbulk_variant_resp(clusterReply *r, int null_mbulk_as_null,
zval *z_ret)
{
zval z_sub_ele;
long long i;
switch(r->type) {
case TYPE_INT:
add_next_index_long(z_ret, r->integer);
break;
case TYPE_LINE:
if (r->str) {
add_next_index_stringl(z_ret, r->str, r->len);
} else {
add_next_index_bool(z_ret, 1);
}
break;
case TYPE_BULK:
if (r->len > -1) {
add_next_index_stringl(z_ret, r->str, r->len);
} else {
add_next_index_null(z_ret);
}
break;
case TYPE_MULTIBULK:
if (r->elements < 0 && null_mbulk_as_null) {
add_next_index_null(z_ret);
} else {
array_init(&z_sub_ele);
for (i = 0; i < r->elements; i++) {
cluster_mbulk_variant_resp(r->element[i], null_mbulk_as_null, &z_sub_ele);
}
add_next_index_zval(z_ret, &z_sub_ele);
}
break;
default:
add_next_index_bool(z_ret, 0);
break;
}
}
/* Variant response handling, for things like EVAL and various other responses
* where we just map the replies from Redis type values to PHP ones directly. */
static void
cluster_variant_resp_generic(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
int status_strings, void *ctx)
{
clusterReply *r;
zval zv, *z_arr = &zv;
long long i;
// Make sure we can read it
if ((r = cluster_read_resp(c, status_strings)) == NULL) {
CLUSTER_RETURN_FALSE(c);
}
// Handle ATOMIC vs. MULTI mode in a separate switch
if (CLUSTER_IS_ATOMIC(c)) {
switch(r->type) {
case TYPE_INT:
RETVAL_LONG(r->integer);
break;
case TYPE_ERR:
RETVAL_FALSE;
break;
case TYPE_LINE:
if (status_strings) {
RETVAL_STRINGL(r->str, r->len);
} else {
RETVAL_TRUE;
}
break;
case TYPE_BULK:
if (r->len < 0) {
RETVAL_NULL();
} else {
RETVAL_STRINGL(r->str, r->len);
}
break;
case TYPE_MULTIBULK:
if (r->elements < 0 && c->flags->null_mbulk_as_null) {
RETVAL_NULL();
} else {
array_init(z_arr);
for (i = 0; i < r->elements; i++) {
cluster_mbulk_variant_resp(r->element[i], c->flags->null_mbulk_as_null, z_arr);
}
RETVAL_ZVAL(z_arr, 0, 0);
}
break;
default:
RETVAL_FALSE;
break;
}
} else {
switch(r->type) {
case TYPE_INT:
add_next_index_long(&c->multi_resp, r->integer);
break;
case TYPE_ERR:
add_next_index_bool(&c->multi_resp, 0);
break;
case TYPE_LINE:
if (status_strings) {
add_next_index_stringl(&c->multi_resp, r->str, r->len);
} else {
add_next_index_bool(&c->multi_resp, 1);
}
break;
case TYPE_BULK:
if (r->len < 0) {
add_next_index_null(&c->multi_resp);
} else {
add_next_index_stringl(&c->multi_resp, r->str, r->len);
}
break;
case TYPE_MULTIBULK:
if (r->elements < 0 && c->flags->null_mbulk_as_null) {
add_next_index_null(&c->multi_resp);
} else {
cluster_mbulk_variant_resp(r, c->flags->null_mbulk_as_null, &c->multi_resp);
}
break;
default:
add_next_index_bool(&c->multi_resp, 0);
break;
}
}
// Free our response structs, but not allocated data itself
cluster_free_reply(r, 1);
}
PHP_REDIS_API void
cluster_zrange_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx) {
cluster_cb cb;
ZEND_ASSERT(ctx == NULL || ctx == PHPREDIS_CTX_PTR);
cb = ctx ? cluster_mbulk_zipdbl_resp : cluster_mbulk_resp;
cb(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, ctx);
}
PHP_REDIS_API void cluster_variant_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx)
{
cluster_variant_resp_generic(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, 0, ctx);
}
PHP_REDIS_API void cluster_variant_raw_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx)
{
cluster_variant_resp_generic(INTERNAL_FUNCTION_PARAM_PASSTHRU, c,
c->flags->reply_literal, ctx);
}
PHP_REDIS_API void cluster_variant_resp_strings(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx)
{
cluster_variant_resp_generic(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, 1, ctx);
}
/* Generic MULTI BULK response processor */
PHP_REDIS_API void cluster_gen_mbulk_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, mbulk_cb cb, void *ctx)
{
zval z_result;
/* Abort if the reply isn't MULTIBULK or has an invalid length */
if (c->reply_type != TYPE_MULTIBULK || c->reply_len < -1) {
CLUSTER_RETURN_FALSE(c);
}
if (c->reply_len == -1 && c->flags->null_mbulk_as_null) {
ZVAL_NULL(&z_result);
} else {
array_init(&z_result);
if (c->reply_len > 0) {
/* Push serialization settings from the cluster into our socket */
c->cmd_sock->serializer = c->flags->serializer;
c->cmd_sock->compression = c->flags->compression;
/* Call our specified callback */
if (cb(c->cmd_sock, &z_result, c->reply_len, ctx) == FAILURE) {
zval_dtor(&z_result);
CLUSTER_RETURN_FALSE(c);
}
}
}
// Success, make this array our return value
if (CLUSTER_IS_ATOMIC(c)) {
RETVAL_ZVAL(&z_result, 0, 1);
} else {
add_next_index_zval(&c->multi_resp, &z_result);
}
}
/* HSCAN, SSCAN, ZSCAN */
PHP_REDIS_API int cluster_scan_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
REDIS_SCAN_TYPE type, long *it)
{
char *pit;
// We always want to see a MULTIBULK response with two elements
if (c->reply_type != TYPE_MULTIBULK || c->reply_len != 2)
{
return FAILURE;
}
// Read the BULK size
if (cluster_check_response(c, &c->reply_type) ||
c->reply_type != TYPE_BULK)
{
return FAILURE;
}
// Read the iterator
if ((pit = redis_sock_read_bulk_reply(c->cmd_sock,c->reply_len)) == NULL)
{
return FAILURE;
}
// Push the new iterator value to our caller
*it = atol(pit);
efree(pit);
// We'll need another MULTIBULK response for the payload
if (cluster_check_response(c, &c->reply_type) < 0)
{
return FAILURE;
}
// Use the proper response callback depending on scan type
switch(type) {
case TYPE_SCAN:
cluster_mbulk_raw_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU,c,NULL);
break;
case TYPE_SSCAN:
cluster_mbulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU,c,NULL);
break;
case TYPE_HSCAN:
cluster_mbulk_zipstr_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU,c,NULL);
break;
case TYPE_ZSCAN:
cluster_mbulk_zipdbl_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU,c,NULL);
break;
default:
return FAILURE;
}
// Success
return SUCCESS;
}
/* INFO response */
PHP_REDIS_API void cluster_info_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx)
{
zval z_result;
char *info;
// Read our bulk response
if ((info = redis_sock_read_bulk_reply(c->cmd_sock, c->reply_len)) == NULL)
{
CLUSTER_RETURN_FALSE(c);
}
/* Parse response, free memory */
redis_parse_info_response(info, &z_result);
efree(info);
// Return our array
if (CLUSTER_IS_ATOMIC(c)) {
RETVAL_ZVAL(&z_result, 0, 1);
} else {
add_next_index_zval(&c->multi_resp, &z_result);
}
}
/* CLIENT LIST response */
PHP_REDIS_API void cluster_client_list_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx)
{
char *info;
zval z_result;
/* Read the bulk response */
info = redis_sock_read_bulk_reply(c->cmd_sock, c->reply_len);
if (info == NULL) {
CLUSTER_RETURN_FALSE(c);
}
/* Parse it and free the bulk string */
redis_parse_client_list_response(info, &z_result);
efree(info);
if (CLUSTER_IS_ATOMIC(c)) {
RETVAL_ZVAL(&z_result, 0, 1);
} else {
add_next_index_zval(&c->multi_resp, &z_result);
}
}
/* XRANGE */
PHP_REDIS_API void
cluster_xrange_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx) {
zval z_messages;
array_init(&z_messages);
c->cmd_sock->serializer = c->flags->serializer;
c->cmd_sock->compression = c->flags->compression;
if (redis_read_stream_messages(c->cmd_sock, c->reply_len, &z_messages) < 0) {
zval_dtor(&z_messages);
CLUSTER_RETURN_FALSE(c);
}
if (CLUSTER_IS_ATOMIC(c)) {
RETVAL_ZVAL(&z_messages, 0, 1);
} else {
add_next_index_zval(&c->multi_resp, &z_messages);
}
}
/* XREAD */
PHP_REDIS_API void
cluster_xread_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx) {
zval z_streams;
c->cmd_sock->serializer = c->flags->serializer;
c->cmd_sock->compression = c->flags->compression;
if (c->reply_len == -1 && c->flags->null_mbulk_as_null) {
ZVAL_NULL(&z_streams);
} else {
array_init(&z_streams);
if (redis_read_stream_messages_multi(c->cmd_sock, c->reply_len, &z_streams) < 0) {
zval_dtor(&z_streams);
CLUSTER_RETURN_FALSE(c);
}
}
if (CLUSTER_IS_ATOMIC(c)) {
RETVAL_ZVAL(&z_streams, 0, 1);
} else {
add_next_index_zval(&c->multi_resp, &z_streams);
}
}
/* XCLAIM */
PHP_REDIS_API void
cluster_xclaim_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx) {
zval z_msg;
array_init(&z_msg);
ZEND_ASSERT(ctx == NULL || ctx == PHPREDIS_CTX_PTR);
if (redis_read_xclaim_reply(c->cmd_sock, c->reply_len, ctx == PHPREDIS_CTX_PTR, &z_msg) < 0) {
zval_dtor(&z_msg);
CLUSTER_RETURN_FALSE(c);
}
if (CLUSTER_IS_ATOMIC(c)) {
RETVAL_ZVAL(&z_msg, 0, 1);
} else {
add_next_index_zval(&c->multi_resp, &z_msg);
}
}
/* XINFO */
PHP_REDIS_API void
cluster_xinfo_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx)
{
zval z_ret;
array_init(&z_ret);
if (redis_read_xinfo_response(c->cmd_sock, &z_ret, c->reply_len) != SUCCESS) {
zval_dtor(&z_ret);
CLUSTER_RETURN_FALSE(c);
}
if (CLUSTER_IS_ATOMIC(c)) {
RETURN_ZVAL(&z_ret, 0, 1);
}
add_next_index_zval(&c->multi_resp, &z_ret);
}
/* LMPOP, ZMPOP, BLMPOP, BZMPOP */
PHP_REDIS_API void
cluster_mpop_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx)
{
zval z_ret;
c->cmd_sock->null_mbulk_as_null = c->flags->null_mbulk_as_null;
if (redis_read_mpop_response(c->cmd_sock, &z_ret, c->reply_len, ctx) == FAILURE) {
CLUSTER_RETURN_FALSE(c);
}
if (CLUSTER_IS_ATOMIC(c)) {
RETURN_ZVAL(&z_ret, 0, 0);
}
add_next_index_zval(&c->multi_resp, &z_ret);
}
static void
cluster_acl_custom_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx,
int (*cb)(RedisSock*, zval*, long))
{
zval z_ret;
array_init(&z_ret);
if (cb(c->cmd_sock, &z_ret, c->reply_len) != SUCCESS) {
zval_dtor(&z_ret);
CLUSTER_RETURN_FALSE(c);
}
if (CLUSTER_IS_ATOMIC(c)) {
RETURN_ZVAL(&z_ret, 0, 1);
}
add_next_index_zval(&c->multi_resp, &z_ret);
}
PHP_REDIS_API void
cluster_acl_getuser_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx) {
cluster_acl_custom_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, ctx, redis_read_acl_getuser_reply);
}
PHP_REDIS_API void
cluster_acl_log_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx) {
cluster_acl_custom_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, ctx, redis_read_acl_log_reply);
}
/* MULTI BULK response loop where we might pull the next one */
PHP_REDIS_API zval *cluster_zval_mbulk_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, int pull, mbulk_cb cb, zval *z_ret)
{
ZVAL_NULL(z_ret);
// Pull our next response if directed
if (pull) {
if (cluster_check_response(c, &c->reply_type) < 0)
{
return NULL;
}
}
// Validate reply type and length
if (c->reply_type != TYPE_MULTIBULK || c->reply_len == -1) {
return NULL;
}
array_init(z_ret);
// Call our callback
if (cb(c->cmd_sock, z_ret, c->reply_len, NULL) == FAILURE) {
zval_dtor(z_ret);
return NULL;
}
return z_ret;
}
/* MULTI MULTI BULK reply (for EXEC) */
PHP_REDIS_API void cluster_multi_mbulk_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx)
{
zval *multi_resp = &c->multi_resp;
array_init(multi_resp);
clusterFoldItem *fi = c->multi_head;
while (fi) {
/* Make sure our transaction didn't fail here */
if (c->multi_len[fi->slot] > -1) {
/* Set the slot where we should look for responses. We don't allow
* failover inside a transaction, so it will be the master we have
* mapped. */
c->cmd_slot = fi->slot;
c->cmd_sock = SLOT_SOCK(c, fi->slot);
if (cluster_check_response(c, &c->reply_type) < 0) {
zval_dtor(multi_resp);
RETURN_FALSE;
}
fi->callback(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, fi->ctx);
} else {
/* Just add false */
add_next_index_bool(multi_resp, 0);
}
fi = fi->next;
}
// Set our return array
zval_dtor(return_value);
RETVAL_ZVAL(multi_resp, 0, 1);
}
/* Generic handler for MGET */
PHP_REDIS_API void cluster_mbulk_mget_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx)
{
clusterMultiCtx *mctx = (clusterMultiCtx*)ctx;
/* Protect against an invalid response type, -1 response length, and failure
* to consume the responses. */
c->cmd_sock->serializer = c->flags->serializer;
c->cmd_sock->compression = c->flags->compression;
short fail = c->reply_type != TYPE_MULTIBULK || c->reply_len == -1 ||
mbulk_resp_loop(c->cmd_sock, mctx->z_multi, c->reply_len, NULL) == FAILURE;
// If we had a failure, pad results with FALSE to indicate failure. Non
// existent keys (e.g. for MGET will come back as NULL)
if (fail) {
while (mctx->count--) {
add_next_index_bool(mctx->z_multi, 0);
}
}
// If this is the tail of our multi command, we can set our returns
if (mctx->last) {
if (CLUSTER_IS_ATOMIC(c)) {
RETVAL_ZVAL(mctx->z_multi, 0, 1);
} else {
add_next_index_zval(&c->multi_resp, mctx->z_multi);
}
efree(mctx->z_multi);
}
// Clean up this context item
efree(mctx);
}
/* Handler for MSETNX */
PHP_REDIS_API void cluster_msetnx_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx)
{
clusterMultiCtx *mctx = (clusterMultiCtx*)ctx;
int real_argc = mctx->count/2;
// Protect against an invalid response type
if (c->reply_type != TYPE_INT) {
php_error_docref(0, E_WARNING,
"Invalid response type for MSETNX");
while (real_argc--) {
add_next_index_bool(mctx->z_multi, 0);
}
return;
}
// Response will be 1/0 per key, so the client can match them up
while (real_argc--) {
add_next_index_long(mctx->z_multi, c->reply_len);
}
// Set return value if it's our last response
if (mctx->last) {
if (CLUSTER_IS_ATOMIC(c)) {
RETVAL_ZVAL(mctx->z_multi, 0, 0);
} else {
add_next_index_zval(&c->multi_resp, mctx->z_multi);
}
efree(mctx->z_multi);
}
// Free multi context
efree(mctx);
}
/* Handler for DEL */
PHP_REDIS_API void cluster_del_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx)
{
clusterMultiCtx *mctx = (clusterMultiCtx*)ctx;
// If we get an invalid reply, inform the client
if (c->reply_type != TYPE_INT) {
php_error_docref(0, E_WARNING,
"Invalid reply type returned for DEL command");
efree(mctx);
return;
}
// Increment by the number of keys deleted
Z_LVAL_P(mctx->z_multi) += c->reply_len;
if (mctx->last) {
if (CLUSTER_IS_ATOMIC(c)) {
ZVAL_LONG(return_value, Z_LVAL_P(mctx->z_multi));
} else {
add_next_index_long(&c->multi_resp, Z_LVAL_P(mctx->z_multi));
}
efree(mctx->z_multi);
}
efree(ctx);
}
/* Handler for MSET */
PHP_REDIS_API void cluster_mset_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx)
{
clusterMultiCtx *mctx = (clusterMultiCtx*)ctx;
// If we get an invalid reply type something very wrong has happened,
// and we have to abort.
if (c->reply_type != TYPE_LINE) {
php_error_docref(0, E_ERROR,
"Invalid reply type returned for MSET command");
zval_dtor(mctx->z_multi);
efree(mctx->z_multi);
efree(mctx);
RETURN_FALSE;
}
// Set our return if it's the last call
if (mctx->last) {
if (CLUSTER_IS_ATOMIC(c)) {
ZVAL_BOOL(return_value, zval_is_true(mctx->z_multi));
} else {
add_next_index_bool(&c->multi_resp, zval_is_true(mctx->z_multi));
}
efree(mctx->z_multi);
}
efree(mctx);
}
/* Raw MULTI BULK reply */
PHP_REDIS_API void
cluster_mbulk_raw_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx)
{
cluster_gen_mbulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c,
mbulk_resp_loop_raw, NULL);
}
/* Unserialize all the things */
PHP_REDIS_API void
cluster_mbulk_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx)
{
cluster_gen_mbulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c,
mbulk_resp_loop, NULL);
}
/* For handling responses where we get key, value, key, value that
* we will turn into key => value, key => value. */
PHP_REDIS_API void
cluster_mbulk_zipstr_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx)
{
cluster_gen_mbulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c,
mbulk_resp_loop_zipstr, NULL);
}
/* Handling key,value to key=>value where the values are doubles */
PHP_REDIS_API void
cluster_mbulk_zipdbl_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx)
{
cluster_gen_mbulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c,
mbulk_resp_loop_zipdbl, NULL);
}
PHP_REDIS_API void
cluster_mbulk_dbl_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx)
{
cluster_gen_mbulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c,
mbulk_resp_loop_dbl, ctx);
}
/* Associate multi bulk response (for HMGET really) */
PHP_REDIS_API void
cluster_mbulk_assoc_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx)
{
cluster_gen_mbulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c,
mbulk_resp_loop_assoc, ctx);
}
/*
* Various MULTI BULK reply callback functions
*/
int mbulk_resp_loop_dbl(RedisSock *redis_sock, zval *z_result,
long long count, void *ctx)
{
char *line;
int line_len;
while (count--) {
line = redis_sock_read(redis_sock, &line_len);
if (line != NULL) {
add_next_index_double(z_result, atof(line));
efree(line);
} else {
add_next_index_bool(z_result, 0);
}
}
return SUCCESS;
}
/* MULTI BULK response where we don't touch the values (e.g. KEYS) */
int mbulk_resp_loop_raw(RedisSock *redis_sock, zval *z_result,
long long count, void *ctx)
{
char *line;
int line_len;
// Iterate over the number we have
while (count--) {
// Read the line, which should never come back null
line = redis_sock_read(redis_sock, &line_len);
if (line == NULL) return FAILURE;
// Add to our result array
add_next_index_stringl(z_result, line, line_len);
efree(line);
}
// Success!
return SUCCESS;
}
/* MULTI BULK response where we unserialize everything */
int mbulk_resp_loop(RedisSock *redis_sock, zval *z_result,
long long count, void *ctx)
{
char *line;
int line_len;
/* Iterate over the lines we have to process */
while (count--) {
/* Read our line */
line = redis_sock_read(redis_sock, &line_len);
if (line != NULL) {
zval z_unpacked;
if (redis_unpack(redis_sock, line, line_len, &z_unpacked)) {
add_next_index_zval(z_result, &z_unpacked);
} else {
add_next_index_stringl(z_result, line, line_len);
}
efree(line);
} else {
add_next_index_bool(z_result, 0);
}
}
return SUCCESS;
}
/* MULTI BULK response where we turn key1,value1 into key1=>value1 */
int mbulk_resp_loop_zipstr(RedisSock *redis_sock, zval *z_result,
long long count, void *ctx)
{
char *line, *key = NULL;
int line_len, key_len = 0;
long long idx = 0;
// Our count will need to be divisible by 2
if (count % 2 != 0) {
return -1;
}
// Iterate through our elements
while (count--) {
// Grab our line, bomb out on failure
line = redis_sock_read(redis_sock, &line_len);
if (!line) return -1;
if (idx++ % 2 == 0) {
// Save our key and length
key = line;
key_len = line_len;
} else {
/* Attempt unpacking */
zval z_unpacked;
if (redis_unpack(redis_sock, line, line_len, &z_unpacked)) {
add_assoc_zval(z_result, key, &z_unpacked);
} else {
add_assoc_stringl_ex(z_result, key, key_len, line, line_len);
}
efree(line);
efree(key);
}
}
return SUCCESS;
}
/* MULTI BULK loop processor where we expect key,score key, score */
int mbulk_resp_loop_zipdbl(RedisSock *redis_sock, zval *z_result,
long long count, void *ctx)
{
char *line, *key = NULL;
int line_len, key_len = 0;
long long idx = 0;
// Our context will need to be divisible by 2
if (count %2 != 0) {
return -1;
}
// While we have elements
while (count--) {
line = redis_sock_read(redis_sock, &line_len);
if (line != NULL) {
if (idx++ % 2 == 0) {
key = line;
key_len = line_len;
} else {
zval zv, *z = &zv;
if (redis_unpack(redis_sock,key,key_len, z)) {
zend_string *zstr = zval_get_string(z);
add_assoc_double_ex(z_result, ZSTR_VAL(zstr), ZSTR_LEN(zstr), atof(line));
zend_string_release(zstr);
zval_dtor(z);
} else {
add_assoc_double_ex(z_result, key, key_len, atof(line));
}
/* Free our key and line */
efree(key);
efree(line);
}
}
}
return SUCCESS;
}
/* MULTI BULK where we're passed the keys, and we attach vals */
int mbulk_resp_loop_assoc(RedisSock *redis_sock, zval *z_result,
long long count, void *ctx)
{
char *line;
int line_len, i;
zval *z_keys = ctx;
// Loop while we've got replies
for (i = 0; i < count; ++i) {
zend_string *zstr = zval_get_string(&z_keys[i]);
line = redis_sock_read(redis_sock, &line_len);
if (line != NULL) {
zval z_unpacked;
if (redis_unpack(redis_sock, line, line_len, &z_unpacked)) {
add_assoc_zval_ex(z_result, ZSTR_VAL(zstr), ZSTR_LEN(zstr), &z_unpacked);
} else {
add_assoc_stringl_ex(z_result, ZSTR_VAL(zstr), ZSTR_LEN(zstr), line, line_len);
}
efree(line);
} else {
add_assoc_bool_ex(z_result, ZSTR_VAL(zstr), ZSTR_LEN(zstr), 0);
}
// Clean up key context
zend_string_release(zstr);
zval_dtor(&z_keys[i]);
}
// Clean up our keys overall
efree(z_keys);
// Success!
return SUCCESS;
}
/* Free an array of zend_string seeds */
void free_seed_array(zend_string **seeds, uint32_t nseeds) {
int i;
if (seeds == NULL)
return;
for (i = 0; i < nseeds; i++)
zend_string_release(seeds[i]);
efree(seeds);
}
static zend_string **get_valid_seeds(HashTable *input, uint32_t *nseeds) {
HashTable *valid;
uint32_t count, idx = 0;
zval *z_seed;
zend_string *zkey, **seeds = NULL;
/* Short circuit if we don't have any sees */
count = zend_hash_num_elements(input);
if (count == 0)
return NULL;
ALLOC_HASHTABLE(valid);
zend_hash_init(valid, count, NULL, NULL, 0);
ZEND_HASH_FOREACH_VAL(input, z_seed) {
ZVAL_DEREF(z_seed);
if (Z_TYPE_P(z_seed) != IS_STRING) {
php_error_docref(NULL, E_WARNING, "Skipping non-string entry in seeds array");
continue;
} else if (strrchr(Z_STRVAL_P(z_seed), ':') == NULL) {
php_error_docref(NULL, E_WARNING,
"Seed '%s' not in host:port format, ignoring", Z_STRVAL_P(z_seed));
continue;
}
/* Add as a key to avoid duplicates */
zend_hash_str_update_ptr(valid, Z_STRVAL_P(z_seed), Z_STRLEN_P(z_seed), NULL);
} ZEND_HASH_FOREACH_END();
/* We need at least one valid seed */
count = zend_hash_num_elements(valid);
if (count == 0)
goto cleanup;
/* Populate our return array */
seeds = ecalloc(count, sizeof(*seeds));
ZEND_HASH_FOREACH_STR_KEY(valid, zkey) {
seeds[idx++] = zend_string_copy(zkey);
} ZEND_HASH_FOREACH_END();
*nseeds = idx;
cleanup:
zend_hash_destroy(valid);
FREE_HASHTABLE(valid);
return seeds;
}
/* Validate cluster construction arguments and return a sanitized and validated
* array of seeds */
zend_string**
cluster_validate_args(double timeout, double read_timeout, HashTable *seeds,
uint32_t *nseeds, char **errstr)
{
zend_string **retval;
if (timeout > INT_MAX) {
if (errstr) *errstr = "Invalid timeout";
return NULL;
}
if (read_timeout > INT_MAX) {
if (errstr) *errstr = "Invalid read timeout";
return NULL;
}
retval = get_valid_seeds(seeds, nseeds);
if (retval == NULL && errstr)
*errstr = "No valid seeds detected";
return retval;
}
/* Helper function to compare to host:port seeds */
static int cluster_cmp_seeds(const void *a, const void *b) {
zend_string *za = *(zend_string **)a;
zend_string *zb = *(zend_string **)b;
return strcmp(ZSTR_VAL(za), ZSTR_VAL(zb));
}
static void cluster_swap_seeds(void *a, void *b) {
zend_string **za, **zb, *tmp;
za = a;
zb = b;
tmp = *za;
*za = *zb;
*zb = tmp;
}
/* Turn an array of cluster seeds into a string we can cache. If we get here we know
* we have at least one entry and that every entry is a string in the form host:port */
#define SLOT_CACHE_PREFIX "phpredis_slots:"
zend_string *cluster_hash_seeds(zend_string **seeds, uint32_t count) {
smart_str hash = {0};
size_t i;
/* Sort our seeds so any any array with identical seeds hashes to the same key
* regardless of what order the user gives them to us in. */
zend_sort(seeds, count, sizeof(*seeds), cluster_cmp_seeds, cluster_swap_seeds);
/* Global phpredis hash prefix */
smart_str_appendl(&hash, SLOT_CACHE_PREFIX, sizeof(SLOT_CACHE_PREFIX) - 1);
/* Construct our actual hash */
for (i = 0; i < count; i++) {
smart_str_appendc(&hash, '[');
smart_str_append_ex(&hash, seeds[i], 0);
smart_str_appendc(&hash, ']');
}
/* Null terminate */
smart_str_0(&hash);
/* Return the internal zend_string */
return hash.s;
}
PHP_REDIS_API redisCachedCluster *cluster_cache_load(zend_string *hash) {
zend_resource *le;
/* Look for cached slot information */
le = zend_hash_find_ptr(&EG(persistent_list), hash);
if (le != NULL) {
/* Sanity check on our list type */
if (le->type == le_cluster_slot_cache) {
/* Success, return the cached entry */
return le->ptr;
}
php_error_docref(0, E_WARNING, "Invalid slot cache resource");
}
/* Not found */
return NULL;
}
/* Cache a cluster's slot information in persistent_list if it's enabled */
PHP_REDIS_API void cluster_cache_store(zend_string *hash, HashTable *nodes) {
redisCachedCluster *cc = cluster_cache_create(hash, nodes);
redis_register_persistent_resource(cc->hash, cc, le_cluster_slot_cache);
}
/* vim: set tabstop=4 softtabstop=4 expandtab shiftwidth=4: */
redis-6.0.2/cluster_library.h 0000644 0001750 0000012 00000046415 14515245367 017010 0 ustar pyatsukhnenko wheel #ifndef _PHPREDIS_CLUSTER_LIBRARY_H
#define _PHPREDIS_CLUSTER_LIBRARY_H
#include "common.h"
#ifdef ZTS
#include "TSRM.h"
#endif
/* Redis cluster hash slots and N-1 which we'll use to find it */
#define REDIS_CLUSTER_SLOTS 16384
#define REDIS_CLUSTER_MOD (REDIS_CLUSTER_SLOTS-1)
/* Complete representation for various commands in RESP */
#define RESP_UNWATCH_CMD "*1\r\n$7\r\nUNWATCH\r\n"
#define RESP_CLUSTER_SLOTS_CMD "*2\r\n$7\r\nCLUSTER\r\n$5\r\nSLOTS\r\n"
#define RESP_ASKING_CMD "*1\r\n$6\r\nASKING\r\n"
#define RESP_READONLY_CMD "*1\r\n$8\r\nREADONLY\r\n"
#define RESP_READWRITE_CMD "*1\r\n$9\r\nREADWRITE\r\n"
#define RESP_READONLY_CMD_LEN (sizeof(RESP_READONLY_CMD)-1)
/* MOVED/ASK comparison macros */
#define IS_MOVED(p) (p[0]=='M' && p[1]=='O' && p[2]=='V' && p[3]=='E' && \
p[4]=='D' && p[5]==' ')
#define IS_ASK(p) (p[0]=='A' && p[1]=='S' && p[2]=='K' && p[3]==' ')
/* MOVED/ASK lengths */
#define MOVED_LEN (sizeof("MOVED ")-1)
#define ASK_LEN (sizeof("ASK ")-1)
/* Initial allocation size for key distribution container */
#define CLUSTER_KEYDIST_ALLOC 8
/* Macros to access nodes, sockets, and streams for a given slot */
#define SLOT(c,s) (c->master[s])
#define SLOT_SOCK(c,s) (SLOT(c,s)->sock)
#define SLOT_STREAM(c,s) (SLOT_SOCK(c,s)->stream)
#define SLOT_SLAVES(c,s) (c->master[s]->slaves)
/* Compare redirection slot information with the passed node */
#define CLUSTER_REDIR_CMP(c, sock) \
(sock->port != c->redir_port || \
ZSTR_LEN(sock->host) != c->redir_host_len || \
memcmp(ZSTR_VAL(sock->host),c->redir_host,c->redir_host_len))
/* Clear out our "last error" */
#define CLUSTER_CLEAR_ERROR(c) do { \
if (c->err) { \
zend_string_release(c->err); \
c->err = NULL; \
} \
c->clusterdown = 0; \
} while (0)
/* Protected sending of data down the wire to a RedisSock->stream */
#define CLUSTER_SEND_PAYLOAD(sock, buf, len) \
(sock && !redis_sock_server_open(sock) && sock->stream && !redis_check_eof(sock, 0, 1) && \
redis_sock_write_raw(sock, buf, len) == len)
/* Macro to read our reply type character */
#define CLUSTER_VALIDATE_REPLY_TYPE(sock, type) \
(redis_check_eof(sock, 1, 1) == 0 && redis_sock_getc(sock) == type)
/* Reset our last single line reply buffer and length */
#define CLUSTER_CLEAR_REPLY(c) \
*c->line_reply = '\0'; c->reply_len = 0;
/* Helper to determine if we're in MULTI mode */
#define CLUSTER_IS_ATOMIC(c) (c->flags->mode != MULTI)
/* Helper that either returns false or adds false in multi mode */
#define CLUSTER_RETURN_FALSE(c) \
if(CLUSTER_IS_ATOMIC(c)) { \
RETURN_FALSE; \
} else { \
add_next_index_bool(&c->multi_resp, 0); \
return; \
}
/* Helper to either return a bool value or add it to MULTI response */
#define CLUSTER_RETURN_BOOL(c, b) \
if(CLUSTER_IS_ATOMIC(c)) { \
RETURN_BOOL(b); \
} else { \
add_next_index_bool(&c->multi_resp, b); \
}
/* Helper to respond with a double or add it to our MULTI response */
#define CLUSTER_RETURN_DOUBLE(c, d) \
if(CLUSTER_IS_ATOMIC(c)) { \
RETURN_DOUBLE(d); \
} else { \
add_next_index_double(&c->multi_resp, d); \
}
/* Helper to return a string value */
#define CLUSTER_RETURN_STRING(c, str, len) \
if(CLUSTER_IS_ATOMIC(c)) { \
RETVAL_STRINGL(str, len); \
} else { \
add_next_index_stringl(&c->multi_resp, str, len); \
} \
/* Return a LONG value */
#define CLUSTER_RETURN_LONG(c, val) \
if(CLUSTER_IS_ATOMIC(c)) { \
RETURN_LONG(val); \
} else { \
add_next_index_long(&c->multi_resp, val); \
}
/* Macro to clear out a clusterMultiCmd structure */
#define CLUSTER_MULTI_CLEAR(mc) \
mc->cmd.len = 0; \
mc->args.len = 0; \
mc->argc = 0; \
/* Initialzie a clusterMultiCmd with a keyword and length */
#define CLUSTER_MULTI_INIT(mc, keyword, keyword_len) \
mc.kw = keyword; \
mc.kw_len = keyword_len; \
#define CLUSTER_CACHING_ENABLED() (INI_INT("redis.clusters.cache_slots") == 1)
/* Cluster redirection enum */
typedef enum CLUSTER_REDIR_TYPE {
REDIR_NONE,
REDIR_MOVED,
REDIR_ASK
} CLUSTER_REDIR_TYPE;
/* MULTI BULK response callback typedef */
typedef int (*mbulk_cb)(RedisSock*,zval*,long long, void*);
/* A list of covered slot ranges */
typedef struct redisSlotRange {
unsigned short low;
unsigned short high;
} redisSlotRange;
/* Simple host/port information for our cache */
typedef struct redisCachedHost {
zend_string *addr;
unsigned short port;
} redisCachedHost;
/* Storage for a cached master node */
typedef struct redisCachedMaster {
redisCachedHost host;
redisSlotRange *slot; /* Slots and count */
size_t slots;
redisCachedHost *slave; /* Slaves and their count */
size_t slaves;
} redisCachedMaster;
typedef struct redisCachedCluster {
// int rsrc_id; /* Zend resource ID */
zend_string *hash; /* What we're cached by */
redisCachedMaster *master; /* Array of masters */
size_t count; /* Number of masters */
} redisCachedCluster;
/* A Redis Cluster master node */
typedef struct redisClusterNode {
RedisSock *sock; /* Our Redis socket in question */
short slot; /* One slot we believe this node serves */
zend_llist slots; /* List of all slots we believe this node serves */
unsigned short slave; /* Are we a slave */
HashTable *slaves; /* Hash table of slaves */
} redisClusterNode;
/* Forward declarations */
typedef struct clusterFoldItem clusterFoldItem;
/* RedisCluster implementation structure */
typedef struct redisCluster {
/* One RedisSock struct for serialization and prefix information */
RedisSock *flags;
/* How long in milliseconds should we wait when being bounced around */
long waitms;
/* Are we flagged as being in readonly mode, meaning we could fall back to
* a given master's slave */
short readonly;
/* RedisCluster failover options (never, on error, to load balance) */
short failover;
/* Hash table of seed host/ports */
HashTable *seeds;
/* RedisCluster masters, by direct slot */
redisClusterNode *master[REDIS_CLUSTER_SLOTS];
/* All RedisCluster objects we've created/are connected to */
HashTable *nodes;
/* Transaction handling linked list, and where we are as we EXEC */
clusterFoldItem *multi_head;
clusterFoldItem *multi_curr;
/* When we issue EXEC to nodes, we need to keep track of how many replies
* we have, as this can fail for various reasons (EXECABORT, watch, etc.) */
char multi_len[REDIS_CLUSTER_SLOTS];
/* Variable to store MULTI response */
zval multi_resp;
/* Flag for when we get a CLUSTERDOWN error */
short clusterdown;
/* Key to our persistent list cache and number of redirections we've
* received since construction */
zend_string *cache_key;
uint64_t redirections;
/* The last ERROR we encountered */
zend_string *err;
/* The slot our command is operating on, as well as it's socket */
unsigned short cmd_slot;
RedisSock *cmd_sock;
/* The slot where we're subscribed */
short subscribed_slot;
/* The first line of our last reply, not including our reply type byte
* or the trailing \r\n */
char line_reply[1024];
/* The last reply type and length or integer response we got */
REDIS_REPLY_TYPE reply_type;
long long reply_len;
/* Last MOVED or ASK redirection response information */
CLUSTER_REDIR_TYPE redir_type;
char redir_host[255];
int redir_host_len;
unsigned short redir_slot;
unsigned short redir_port;
/* Zend object handler */
zend_object std;
} redisCluster;
/* RedisCluster response processing callback */
typedef void (*cluster_cb)(INTERNAL_FUNCTION_PARAMETERS, redisCluster*, void*);
/* Context for processing transactions */
struct clusterFoldItem {
/* Response processing callback */
cluster_cb callback;
/* The actual socket where we send this request */
unsigned short slot;
/* Any context we need to send to our callback */
void *ctx;
/* Next item in our list */
struct clusterFoldItem *next;
};
/* Key and value container, with info if they need freeing */
typedef struct clusterKeyVal {
char *key, *val;
int key_len, val_len;
int key_free, val_free;
} clusterKeyVal;
/* Container to hold keys (and possibly values) for when we need to distribute
* commands across more than 1 node (e.g. WATCH, MGET, MSET, etc) */
typedef struct clusterDistList {
clusterKeyVal *entry;
size_t len, size;
} clusterDistList;
/* Context for things like MGET/MSET/MSETNX. When executing in MULTI mode,
* we'll want to re-integrate into one running array, except for the last
* command execution, in which we'll want to return the value (or add it) */
typedef struct clusterMultiCtx {
/* Our running array */
zval *z_multi;
/* How many keys did we request for this bit */
int count;
/* Is this the last entry */
short last;
} clusterMultiCtx;
/* Container for things like MGET, MSET, and MSETNX, which split the command
* into a header and payload while aggregating to a specific slot. */
typedef struct clusterMultiCmd {
/* Keyword and keyword length */
char *kw;
int kw_len;
/* Arguments in our payload */
int argc;
/* The full command, built into cmd, and args as we aggregate */
smart_string cmd;
smart_string args;
} clusterMultiCmd;
/* Hiredis like structure for processing any sort of reply Redis Cluster might
* give us, including N level deep nested multi-bulk replies. Unlike hiredis
* we don't encode errors, here as that's handled in the cluster structure. */
typedef struct clusterReply {
REDIS_REPLY_TYPE type; /* Our reply type */
size_t integer; /* Integer reply */
long long len; /* Length of our string */
char *str; /* String reply */
long long elements; /* Count of array elements */
struct clusterReply **element; /* Array elements */
} clusterReply;
/* Direct variant response handler */
clusterReply *cluster_read_resp(redisCluster *c, int status_strings);
clusterReply *cluster_read_sock_resp(RedisSock *redis_sock,
REDIS_REPLY_TYPE type, char *line_reply, long long reply_len);
void cluster_free_reply(clusterReply *reply, int free_data);
/* Cluster distribution helpers for WATCH */
HashTable *cluster_dist_create(void);
void cluster_dist_free(HashTable *ht);
int cluster_dist_add_key(redisCluster *c, HashTable *ht, char *key,
size_t key_len, clusterKeyVal **kv);
void cluster_dist_add_val(redisCluster *c, clusterKeyVal *kv, zval *val
);
/* Aggregation for multi commands like MGET, MSET, and MSETNX */
void cluster_multi_init(clusterMultiCmd *mc, char *kw, int kw_len);
void cluster_multi_free(clusterMultiCmd *mc);
void cluster_multi_add(clusterMultiCmd *mc, char *data, int data_len);
void cluster_multi_fini(clusterMultiCmd *mc);
/* Hash a key to it's slot, using the Redis Cluster hash algorithm */
unsigned short cluster_hash_key_zval(zval *key);
unsigned short cluster_hash_key(const char *key, int len);
unsigned short cluster_hash_key_zstr(zend_string *key);
/* Validate and sanitize cluster construction args */
zend_string** cluster_validate_args(double timeout, double read_timeout,
HashTable *seeds, uint32_t *nseeds, char **errstr);
void free_seed_array(zend_string **seeds, uint32_t nseeds);
/* Generate a unique hash string from seeds array */
zend_string *cluster_hash_seeds(zend_string **seeds, uint32_t nseeds);
/* Get the current time in milliseconds */
long long mstime(void);
PHP_REDIS_API short cluster_send_command(redisCluster *c, short slot, const char *cmd,
int cmd_len);
PHP_REDIS_API void cluster_disconnect(redisCluster *c, int force);
PHP_REDIS_API int cluster_send_exec(redisCluster *c, short slot);
PHP_REDIS_API int cluster_send_discard(redisCluster *c, short slot);
PHP_REDIS_API int cluster_abort_exec(redisCluster *c);
PHP_REDIS_API short cluster_find_slot(redisCluster *c, const char *host,
unsigned short port);
PHP_REDIS_API int cluster_send_slot(redisCluster *c, short slot, char *cmd,
int cmd_len, REDIS_REPLY_TYPE rtype);
PHP_REDIS_API redisCluster *cluster_create(double timeout, double read_timeout,
int failover, int persistent);
PHP_REDIS_API void cluster_free(redisCluster *c, int free_ctx);
PHP_REDIS_API void cluster_init_seeds(redisCluster *c, zend_string **seeds, uint32_t nseeds);
PHP_REDIS_API int cluster_map_keyspace(redisCluster *c);
PHP_REDIS_API void cluster_free_node(redisClusterNode *node);
/* Functions for interacting with cached slots maps */
PHP_REDIS_API redisCachedCluster *cluster_cache_create(zend_string *hash, HashTable *nodes);
PHP_REDIS_API void cluster_cache_free(redisCachedCluster *rcc);
PHP_REDIS_API void cluster_init_cache(redisCluster *c, redisCachedCluster *rcc);
/* Functions to facilitate cluster slot caching */
PHP_REDIS_API char **cluster_sock_read_multibulk_reply(RedisSock *redis_sock, int *len);
PHP_REDIS_API void cluster_cache_store(zend_string *hash, HashTable *nodes);
PHP_REDIS_API redisCachedCluster *cluster_cache_load(zend_string *hash);
/*
* Redis Cluster response handlers. Our response handlers generally take the
* following form:
* PHP_REDIS_API void handler(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
* void *ctx)
*
* Reply handlers are responsible for setting the PHP return value (either to
* something valid, or FALSE in the case of some failures).
*/
PHP_REDIS_API void cluster_bool_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx);
PHP_REDIS_API void cluster_ping_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx);
PHP_REDIS_API void cluster_pop_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx);
PHP_REDIS_API void cluster_object_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx);
PHP_REDIS_API void cluster_lpos_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx);
PHP_REDIS_API void cluster_hrandfield_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx);
PHP_REDIS_API void cluster_zdiff_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx);
PHP_REDIS_API void cluster_zadd_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx);
PHP_REDIS_API void cluster_zrandmember_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx);
PHP_REDIS_API void cluster_srandmember_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx);
PHP_REDIS_API void cluster_set_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx);
PHP_REDIS_API void cluster_geosearch_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx);
PHP_REDIS_API void cluster_single_line_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx);
PHP_REDIS_API void cluster_bulk_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx);
PHP_REDIS_API void cluster_bulk_raw_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx);
PHP_REDIS_API void cluster_dbl_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx);
PHP_REDIS_API void cluster_1_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx);
PHP_REDIS_API void cluster_long_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx);
PHP_REDIS_API void cluster_type_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx);
PHP_REDIS_API void cluster_sub_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx);
PHP_REDIS_API void cluster_unsub_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx);
PHP_REDIS_API void cluster_zrange_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx);
PHP_REDIS_API void cluster_variant_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx);
PHP_REDIS_API void cluster_variant_raw_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx);
PHP_REDIS_API void cluster_variant_resp_strings(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx);
/* MULTI BULK response functions */
PHP_REDIS_API void cluster_gen_mbulk_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, mbulk_cb func, void *ctx);
PHP_REDIS_API void cluster_mbulk_raw_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx);
PHP_REDIS_API void cluster_mbulk_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx);
PHP_REDIS_API void cluster_mbulk_zipstr_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx);
PHP_REDIS_API void cluster_mbulk_zipdbl_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx);
PHP_REDIS_API void cluster_mbulk_dbl_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx);
PHP_REDIS_API void cluster_mbulk_assoc_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx);
PHP_REDIS_API void cluster_multi_mbulk_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx);
PHP_REDIS_API zval *cluster_zval_mbulk_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, int pull, mbulk_cb cb, zval *z_ret);
/* Handlers for things like DEL/MGET/MSET/MSETNX */
PHP_REDIS_API void cluster_del_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx);
PHP_REDIS_API void cluster_mbulk_mget_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx);
PHP_REDIS_API void cluster_mset_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx);
PHP_REDIS_API void cluster_msetnx_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx);
/* Response handler for ZSCAN, SSCAN, and HSCAN */
PHP_REDIS_API int cluster_scan_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, REDIS_SCAN_TYPE type, long *it);
/* INFO response handler */
PHP_REDIS_API void cluster_info_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx);
/* CLIENT LIST response handler */
PHP_REDIS_API void cluster_client_list_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx);
/* Custom STREAM handlers */
PHP_REDIS_API void cluster_xread_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx);
PHP_REDIS_API void cluster_xrange_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx);
PHP_REDIS_API void cluster_xclaim_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx);
PHP_REDIS_API void cluster_xinfo_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx);
PHP_REDIS_API void cluster_mpop_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx);
/* Custom ACL handlers */
PHP_REDIS_API void cluster_acl_getuser_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx);
PHP_REDIS_API void cluster_acl_log_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx);
/* MULTI BULK processing callbacks */
int mbulk_resp_loop(RedisSock *redis_sock, zval *z_result,
long long count, void *ctx);
int mbulk_resp_loop_raw(RedisSock *redis_sock, zval *z_result,
long long count, void *ctx);
int mbulk_resp_loop_zipstr(RedisSock *redis_sock, zval *z_result,
long long count, void *ctx);
int mbulk_resp_loop_dbl(RedisSock *redis_sock, zval *z_result,
long long count, void *ctx);
int mbulk_resp_loop_zipdbl(RedisSock *redis_sock, zval *z_result,
long long count, void *ctx);
int mbulk_resp_loop_assoc(RedisSock *redis_sock, zval *z_result,
long long count, void *ctx);
#endif
/* vim: set tabstop=4 softtabstop=4 expandtab shiftwidth=4: */
redis-6.0.2/common.h 0000644 0001750 0000012 00000025657 14515245367 015100 0 ustar pyatsukhnenko wheel #include "php.h"
#include "php_ini.h"
#ifndef REDIS_COMMON_H
#define REDIS_COMMON_H
#define PHPREDIS_CTX_PTR ((char *)0xDEADC0DE)
#define PHPREDIS_NOTUSED(v) ((void)v)
#include "zend_llist.h"
#include
#include
#include
#include
#define PHPREDIS_GET_OBJECT(class_entry, o) (class_entry *)((char *)o - XtOffsetOf(class_entry, std))
#define PHPREDIS_ZVAL_GET_OBJECT(class_entry, z) PHPREDIS_GET_OBJECT(class_entry, Z_OBJ_P(z))
/* We'll fallthrough if we want to */
#ifndef __has_attribute
#define __has_attribute(x) 0
#endif
#if __has_attribute(__fallthrough__)
#define REDIS_FALLTHROUGH __attribute__((__fallthrough__))
#else
#define REDIS_FALLTHROUGH do { } while (0)
#endif
/* NULL check so Eclipse doesn't go crazy */
#ifndef NULL
#define NULL ((void *) 0)
#endif
#include "backoff.h"
typedef enum {
REDIS_SOCK_STATUS_FAILED = -1,
REDIS_SOCK_STATUS_DISCONNECTED,
REDIS_SOCK_STATUS_CONNECTED,
REDIS_SOCK_STATUS_AUTHENTICATED,
REDIS_SOCK_STATUS_READY
} redis_sock_status;
#define _NL "\r\n"
/* properties */
#define REDIS_NOT_FOUND 0
#define REDIS_STRING 1
#define REDIS_SET 2
#define REDIS_LIST 3
#define REDIS_ZSET 4
#define REDIS_HASH 5
#define REDIS_STREAM 6
#ifdef PHP_WIN32
#define PHP_REDIS_API __declspec(dllexport)
#define phpredis_atoi64(p) _atoi64((p))
#else
#define PHP_REDIS_API
#define phpredis_atoi64(p) atoll((p))
#endif
/* reply types */
typedef enum _REDIS_REPLY_TYPE {
TYPE_EOF = -1,
TYPE_LINE = '+',
TYPE_INT = ':',
TYPE_ERR = '-',
TYPE_BULK = '$',
TYPE_MULTIBULK = '*'
} REDIS_REPLY_TYPE;
/* SCAN variants */
typedef enum _REDIS_SCAN_TYPE {
TYPE_SCAN,
TYPE_SSCAN,
TYPE_HSCAN,
TYPE_ZSCAN
} REDIS_SCAN_TYPE;
/* PUBSUB subcommands */
typedef enum _PUBSUB_TYPE {
PUBSUB_CHANNELS,
PUBSUB_NUMSUB,
PUBSUB_NUMPAT
} PUBSUB_TYPE;
#define REDIS_SUBSCRIBE_IDX 0
#define REDIS_PSUBSCRIBE_IDX 1
#define REDIS_SSUBSCRIBE_IDX 2
#define REDIS_SUBS_BUCKETS 3
/* options */
#define REDIS_OPT_SERIALIZER 1
#define REDIS_OPT_PREFIX 2
#define REDIS_OPT_READ_TIMEOUT 3
#define REDIS_OPT_SCAN 4
#define REDIS_OPT_FAILOVER 5
#define REDIS_OPT_TCP_KEEPALIVE 6
#define REDIS_OPT_COMPRESSION 7
#define REDIS_OPT_REPLY_LITERAL 8
#define REDIS_OPT_COMPRESSION_LEVEL 9
#define REDIS_OPT_NULL_MBULK_AS_NULL 10
#define REDIS_OPT_MAX_RETRIES 11
#define REDIS_OPT_BACKOFF_ALGORITHM 12
#define REDIS_OPT_BACKOFF_BASE 13
#define REDIS_OPT_BACKOFF_CAP 14
/* cluster options */
#define REDIS_FAILOVER_NONE 0
#define REDIS_FAILOVER_ERROR 1
#define REDIS_FAILOVER_DISTRIBUTE 2
#define REDIS_FAILOVER_DISTRIBUTE_SLAVES 3
/* serializers */
typedef enum {
REDIS_SERIALIZER_NONE,
REDIS_SERIALIZER_PHP,
REDIS_SERIALIZER_IGBINARY,
REDIS_SERIALIZER_MSGPACK,
REDIS_SERIALIZER_JSON
} redis_serializer;
/* compression */
#define REDIS_COMPRESSION_NONE 0
#define REDIS_COMPRESSION_LZF 1
#define REDIS_COMPRESSION_ZSTD 2
#define REDIS_COMPRESSION_LZ4 3
/* SCAN options */
#define REDIS_SCAN_NORETRY 0
#define REDIS_SCAN_RETRY 1
#define REDIS_SCAN_PREFIX 2
#define REDIS_SCAN_NOPREFIX 3
/* BACKOFF_ALGORITHM options */
#define REDIS_BACKOFF_ALGORITHMS 7
#define REDIS_BACKOFF_ALGORITHM_DEFAULT 0
#define REDIS_BACKOFF_ALGORITHM_DECORRELATED_JITTER 1
#define REDIS_BACKOFF_ALGORITHM_FULL_JITTER 2
#define REDIS_BACKOFF_ALGORITHM_EQUAL_JITTER 3
#define REDIS_BACKOFF_ALGORITHM_EXPONENTIAL 4
#define REDIS_BACKOFF_ALGORITHM_UNIFORM 5
#define REDIS_BACKOFF_ALGORITHM_CONSTANT 6
/* GETBIT/SETBIT offset range limits */
#define BITOP_MIN_OFFSET 0
#define BITOP_MAX_OFFSET 4294967295U
/* Transaction modes */
#define ATOMIC 0
#define MULTI 1
#define PIPELINE 2
#define PHPREDIS_DEBUG_LOGGING 0
#if PHP_VERSION_ID < 80000
#define Z_PARAM_ARRAY_HT_OR_NULL(dest) \
Z_PARAM_ARRAY_HT_EX(dest, 1, 0)
#define Z_PARAM_STR_OR_NULL(dest) \
Z_PARAM_STR_EX(dest, 1, 0)
#define Z_PARAM_ZVAL_OR_NULL(dest) \
Z_PARAM_ZVAL_EX(dest, 1, 0)
#define Z_PARAM_BOOL_OR_NULL(dest, is_null) \
Z_PARAM_BOOL_EX(dest, is_null, 1, 0)
#endif
#if PHPREDIS_DEBUG_LOGGING == 1
#define redisDbgFmt(fmt, ...) \
php_printf("%s:%d:%s(): " fmt "\n", __FILE__, __LINE__, __func__, __VA_ARGS__)
#define redisDbgStr(str) phpredisDebugFmt("%s", str)
#else
#define redisDbgFmt(fmt, ...) ((void)0)
#define redisDbgStr(str) ((void)0)
#endif
#define IS_ATOMIC(redis_sock) (redis_sock->mode == ATOMIC)
#define IS_MULTI(redis_sock) (redis_sock->mode & MULTI)
#define IS_PIPELINE(redis_sock) (redis_sock->mode & PIPELINE)
#define PIPELINE_ENQUEUE_COMMAND(cmd, cmd_len) do { \
if (redis_sock->pipeline_cmd == NULL) { \
redis_sock->pipeline_cmd = zend_string_init(cmd, cmd_len, 0); \
} else { \
size_t pipeline_len = ZSTR_LEN(redis_sock->pipeline_cmd); \
redis_sock->pipeline_cmd = zend_string_realloc(redis_sock->pipeline_cmd, pipeline_len + cmd_len, 0); \
memcpy(&ZSTR_VAL(redis_sock->pipeline_cmd)[pipeline_len], cmd, cmd_len); \
} \
} while (0)
#define SOCKET_WRITE_COMMAND(redis_sock, cmd, cmd_len) \
if(redis_sock_write(redis_sock, cmd, cmd_len) < 0) { \
efree(cmd); \
RETURN_FALSE; \
}
#define REDIS_SAVE_CALLBACK(callback, closure_context) do { \
fold_item *fi = malloc(sizeof(fold_item)); \
fi->fun = callback; \
fi->ctx = closure_context; \
fi->next = NULL; \
if (redis_sock->current) { \
redis_sock->current->next = fi; \
} \
redis_sock->current = fi; \
if (NULL == redis_sock->head) { \
redis_sock->head = redis_sock->current; \
} \
} while (0)
#define REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len) \
if (IS_PIPELINE(redis_sock)) { \
PIPELINE_ENQUEUE_COMMAND(cmd, cmd_len); \
} else { \
SOCKET_WRITE_COMMAND(redis_sock, cmd, cmd_len); \
} \
efree(cmd);
#define REDIS_PROCESS_RESPONSE_CLOSURE(function, closure_context) \
if (!IS_PIPELINE(redis_sock)) { \
if (redis_response_enqueued(redis_sock) != SUCCESS) { \
RETURN_FALSE; \
} \
} \
REDIS_SAVE_CALLBACK(function, closure_context); \
RETURN_ZVAL(getThis(), 1, 0); \
#define REDIS_PROCESS_RESPONSE(function) else { \
REDIS_PROCESS_RESPONSE_CLOSURE(function, NULL) \
}
/* Process a command assuming our command where our command building
* function is redis__cmd */
#define REDIS_PROCESS_CMD(cmdname, resp_func) \
RedisSock *redis_sock; char *cmd; int cmd_len; void *ctx=NULL; \
if ((redis_sock = redis_sock_get(getThis(), 0)) == NULL || \
redis_##cmdname##_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU,redis_sock, \
&cmd, &cmd_len, NULL, &ctx)==FAILURE) { \
RETURN_FALSE; \
} \
REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len); \
if (IS_ATOMIC(redis_sock)) { \
resp_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL, ctx); \
} else { \
REDIS_PROCESS_RESPONSE_CLOSURE(resp_func, ctx) \
}
/* Process a command but with a specific command building function
* and keyword which is passed to us*/
#define REDIS_PROCESS_KW_CMD(kw, cmdfunc, resp_func) \
RedisSock *redis_sock; char *cmd; int cmd_len; void *ctx=NULL; \
if ((redis_sock = redis_sock_get(getThis(), 0)) == NULL || \
cmdfunc(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, kw, &cmd, \
&cmd_len, NULL, &ctx)==FAILURE) { \
RETURN_FALSE; \
} \
REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len); \
if (IS_ATOMIC(redis_sock)) { \
resp_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL, ctx); \
} else { \
REDIS_PROCESS_RESPONSE_CLOSURE(resp_func, ctx) \
}
/* Case sensitive compare against compile-time static string */
#define REDIS_STRCMP_STATIC(s, len, sstr) \
(len == sizeof(sstr) - 1 && !strncmp(s, sstr, len))
/* Case insensitive compare against compile-time static string */
#define REDIS_STRICMP_STATIC(s, len, sstr) \
(len == sizeof(sstr) - 1 && !strncasecmp(s, sstr, len))
/* Test if a zval is a string and (case insensitive) matches a static string */
#define ZVAL_STRICMP_STATIC(zv, sstr) \
REDIS_STRICMP_STATIC(Z_STRVAL_P(zv), Z_STRLEN_P(zv), sstr)
/* Case insensitive compare of a zend_string to a static string */
#define ZSTR_STRICMP_STATIC(zs, sstr) \
REDIS_STRICMP_STATIC(ZSTR_VAL(zs), ZSTR_LEN(zs), sstr)
#define REDIS_ENABLE_MODE(redis_sock, m) (redis_sock->mode |= m)
#define REDIS_DISABLE_MODE(redis_sock, m) (redis_sock->mode &= ~m)
/* HOST_NAME_MAX doesn't exist everywhere */
#ifndef HOST_NAME_MAX
#if defined(_POSIX_HOST_NAME_MAX)
#define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
#elif defined(MAXHOSTNAMELEN)
#define HOST_NAME_MAX MAXHOSTNAMELEN
#else
#define HOST_NAME_MAX 255
#endif
#endif
/* Complete representation for various commands in RESP */
#define RESP_MULTI_CMD "*1\r\n$5\r\nMULTI\r\n"
#define RESP_EXEC_CMD "*1\r\n$4\r\nEXEC\r\n"
#define RESP_DISCARD_CMD "*1\r\n$7\r\nDISCARD\r\n"
/* {{{ struct RedisSock */
typedef struct {
php_stream *stream;
php_stream_context *stream_ctx;
zend_string *host;
int port;
zend_string *user;
zend_string *pass;
double timeout;
double read_timeout;
long retry_interval;
int max_retries;
struct RedisBackoff backoff;
redis_sock_status status;
int persistent;
int watching;
zend_string *persistent_id;
HashTable *subs[REDIS_SUBS_BUCKETS];
redis_serializer serializer;
int compression;
int compression_level;
long dbNumber;
zend_string *prefix;
short mode;
struct fold_item *head;
struct fold_item *current;
zend_string *pipeline_cmd;
zend_string *err;
int scan;
int readonly;
int reply_literal;
int null_mbulk_as_null;
int tcp_keepalive;
int sentinel;
size_t txBytes;
size_t rxBytes;
} RedisSock;
/* }}} */
/* Redis response handler function callback prototype */
typedef void (*ResultCallback)(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
typedef int (*FailableResultCallback)(INTERNAL_FUNCTION_PARAMETERS, RedisSock*, zval*, void*);
typedef struct fold_item {
FailableResultCallback fun;
void *ctx;
struct fold_item *next;
} fold_item;
typedef struct {
zend_llist list;
int nb_active;
} ConnectionPool;
typedef struct {
RedisSock *sock;
zend_object std;
} redis_object;
extern const zend_function_entry *redis_get_methods(void);
#endif
redis-6.0.2/config.m4 0000644 0001750 0000012 00000025256 14515245367 015141 0 ustar pyatsukhnenko wheel dnl $Id$
dnl config.m4 for extension redis
PHP_ARG_ENABLE(redis, whether to enable redis support,
dnl Make sure that the comment is aligned:
[ --enable-redis Enable redis support])
PHP_ARG_ENABLE(redis-session, whether to enable sessions,
[ --disable-redis-session Disable session support], yes, no)
PHP_ARG_ENABLE(redis-json, whether to enable json serializer support,
[ --disable-redis-json Disable json serializer support], yes, no)
PHP_ARG_ENABLE(redis-igbinary, whether to enable igbinary serializer support,
[ --enable-redis-igbinary Enable igbinary serializer support], no, no)
PHP_ARG_ENABLE(redis-msgpack, whether to enable msgpack serializer support,
[ --enable-redis-msgpack Enable msgpack serializer support], no, no)
PHP_ARG_ENABLE(redis-lzf, whether to enable lzf compression,
[ --enable-redis-lzf Enable lzf compression support], no, no)
PHP_ARG_WITH(liblzf, use system liblzf,
[ --with-liblzf[=DIR] Use system liblzf], no, no)
PHP_ARG_ENABLE(redis-zstd, whether to enable Zstd compression,
[ --enable-redis-zstd Enable Zstd compression support], no, no)
PHP_ARG_WITH(libzstd, use system libzstd,
[ --with-libzstd[=DIR] Use system libzstd], yes, no)
PHP_ARG_ENABLE(redis-lz4, whether to enable lz4 compression,
[ --enable-redis-lz4 Enable lz4 compression support], no, no)
PHP_ARG_WITH(liblz4, use system liblz4,
[ --with-liblz4[=DIR] Use system liblz4], no, no)
if test "$PHP_REDIS" != "no"; then
if test "$PHP_REDIS_SESSION" != "no"; then
AC_DEFINE(PHP_SESSION,1,[redis sessions])
fi
AC_MSG_CHECKING([for hash includes])
hash_inc_path=""
if test -f "$abs_srcdir/include/php/ext/hash/php_hash.h"; then
hash_inc_path="$abs_srcdir/include/php"
elif test -f "$abs_srcdir/ext/hash/php_hash.h"; then
hash_inc_path="$abs_srcdir"
elif test -f "$phpincludedir/ext/hash/php_hash.h"; then
hash_inc_path="$phpincludedir"
else
for i in php php7; do
if test -f "$prefix/include/$i/ext/hash/php_hash.h"; then
hash_inc_path="$prefix/include/$i"
fi
done
fi
if test "$hash_inc_path" = ""; then
AC_MSG_ERROR([Cannot find php_hash.h])
else
AC_MSG_RESULT([$hash_inc_path])
fi
if test "$PHP_REDIS_JSON" != "no"; then
AC_MSG_CHECKING([for json includes])
json_inc_path=""
if test -f "$abs_srcdir/include/php/ext/json/php_json.h"; then
json_inc_path="$abs_srcdir/include/php"
elif test -f "$abs_srcdir/ext/json/php_json.h"; then
json_inc_path="$abs_srcdir"
elif test -f "$phpincludedir/ext/json/php_json.h"; then
json_inc_path="$phpincludedir"
else
for i in php php7; do
if test -f "$prefix/include/$i/ext/json/php_json.h"; then
json_inc_path="$prefix/include/$i"
fi
done
fi
if test "$json_inc_path" = ""; then
AC_MSG_ERROR([Cannot find php_json.h])
else
AC_MSG_RESULT([$json_inc_path])
fi
fi
AC_MSG_CHECKING([for redis json support])
if test "$PHP_REDIS_JSON" != "no"; then
AC_MSG_RESULT([enabled])
AC_DEFINE(HAVE_REDIS_JSON,1,[Whether redis json serializer is enabled])
JSON_INCLUDES="-I$json_inc_path"
JSON_EXT_DIR="$json_inc_path/ext"
ifdef([PHP_ADD_EXTENSION_DEP],
[
PHP_ADD_EXTENSION_DEP(redis, json)
])
PHP_ADD_INCLUDE($JSON_EXT_DIR)
else
JSON_INCLUDES=""
AC_MSG_RESULT([disabled])
fi
if test "$PHP_REDIS_IGBINARY" != "no"; then
AC_MSG_CHECKING([for igbinary includes])
igbinary_inc_path=""
if test -f "$abs_srcdir/include/php/ext/igbinary/igbinary.h"; then
igbinary_inc_path="$abs_srcdir/include/php"
elif test -f "$abs_srcdir/ext/igbinary/igbinary.h"; then
igbinary_inc_path="$abs_srcdir"
elif test -f "$phpincludedir/ext/igbinary/igbinary.h"; then
igbinary_inc_path="$phpincludedir"
else
for i in php php7; do
if test -f "$prefix/include/$i/ext/igbinary/igbinary.h"; then
igbinary_inc_path="$prefix/include/$i"
fi
done
fi
if test "$igbinary_inc_path" = ""; then
AC_MSG_ERROR([Cannot find igbinary.h])
else
AC_MSG_RESULT([$igbinary_inc_path])
fi
fi
AC_MSG_CHECKING([for redis igbinary support])
if test "$PHP_REDIS_IGBINARY" != "no"; then
AC_MSG_RESULT([enabled])
AC_DEFINE(HAVE_REDIS_IGBINARY,1,[Whether redis igbinary serializer is enabled])
IGBINARY_INCLUDES="-I$igbinary_inc_path"
IGBINARY_EXT_DIR="$igbinary_inc_path/ext"
ifdef([PHP_ADD_EXTENSION_DEP],
[
PHP_ADD_EXTENSION_DEP(redis, igbinary)
])
PHP_ADD_INCLUDE($IGBINARY_EXT_DIR)
else
IGBINARY_INCLUDES=""
AC_MSG_RESULT([disabled])
fi
if test "$PHP_REDIS_MSGPACK" != "no"; then
AC_MSG_CHECKING([for msgpack includes])
msgpack_inc_path=""
if test -f "$abs_srcdir/include/php/ext/msgpack/php_msgpack.h"; then
msgpack_inc_path="$abs_srcdir/include/php"
elif test -f "$abs_srcdir/ext/msgpack/php_msgpack.h"; then
msgpack_inc_path="$abs_srcdir"
elif test -f "$phpincludedir/ext/msgpack/php_msgpack.h"; then
msgpack_inc_path="$phpincludedir"
else
for i in php php7; do
if test -f "$prefix/include/$i/ext/msgpack/php_msgpack.h"; then
msgpack_inc_path="$prefix/include/$i"
fi
done
fi
if test "$msgpack_inc_path" = ""; then
AC_MSG_ERROR([Cannot find php_msgpack.h])
else
AC_MSG_RESULT([$msgpack_inc_path])
fi
fi
if test "$PHP_REDIS_MSGPACK" != "no"; then
AC_MSG_CHECKING([for php msgpack version >= 2.0.3])
MSGPACK_VERSION=`$EGREP "define PHP_MSGPACK_VERSION" $msgpack_inc_path/ext/msgpack/php_msgpack.h | $SED -e 's/[[^0-9\.]]//g'`
if test `echo $MSGPACK_VERSION | $SED -e 's/[[^0-9]]/ /g' | $AWK '{print $1*1000 + $2*100 + $3*10 + $4}'` -lt 2030; then
AC_MSG_ERROR([version >= 2.0.3 required])
else
AC_MSG_RESULT([yes])
fi
AC_DEFINE(HAVE_REDIS_MSGPACK,1,[Whether redis msgpack serializer is enabled])
MSGPACK_INCLUDES="-I$msgpack_inc_path"
MSGPACK_EXT_DIR="$msgpack_inc_path/ext"
ifdef([PHP_ADD_EXTENSION_DEP],
[
PHP_ADD_EXTENSION_DEP(redis, msgpack)
])
PHP_ADD_INCLUDE($MSGPACK_EXT_DIR)
else
MSGPACK_INCLUDES=""
fi
AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
if test "$PHP_REDIS_LZF" != "no"; then
AC_DEFINE(HAVE_REDIS_LZF, 1, [ ])
if test "$PHP_LIBLZF" = "yes" && test -x "$PKG_CONFIG" && $PKG_CONFIG --exists liblzf; then
AC_MSG_CHECKING(for liblzf using pkg-config)
LIBLZF_INC=`$PKG_CONFIG liblzf --cflags`
LIBLZF_LIB=`$PKG_CONFIG liblzf --libs`
LIBLZF_VER=`$PKG_CONFIG liblzf --modversion`
AC_MSG_RESULT(found version $LIBLZF_VER)
PHP_EVAL_LIBLINE($LIBLZF_LIB, REDIS_SHARED_LIBADD)
PHP_EVAL_INCLINE($LIBLZF_INC)
elif test "$PHP_LIBLZF" != "no"; then
AC_MSG_CHECKING(for liblzf files in default path)
for i in $PHP_LIBLZF /usr/local /usr; do
if test -r $i/include/lzf.h; then
AC_MSG_RESULT(found in $i)
LIBLZF_DIR=$i
break
fi
done
if test -z "$LIBLZF_DIR"; then
AC_MSG_RESULT([not found])
AC_MSG_ERROR([Please reinstall the liblzf distribution])
fi
PHP_CHECK_LIBRARY(lzf, lzf_compress,
[
PHP_ADD_LIBRARY_WITH_PATH(lzf, $LIBLZF_DIR/$PHP_LIBDIR, REDIS_SHARED_LIBADD)
], [
AC_MSG_ERROR([could not find usable liblzf])
], [
-L$LIBLZF_DIR/$PHP_LIBDIR
])
else
PHP_ADD_INCLUDE(liblzf)
PHP_ADD_INCLUDE($srcdir/liblzf)
PHP_ADD_BUILD_DIR(liblzf)
lzf_sources="liblzf/lzf_c.c liblzf/lzf_d.c"
fi
fi
if test "$PHP_REDIS_LZ4" != "no"; then
AC_DEFINE(HAVE_REDIS_LZ4, 1, [ ])
if test "$PHP_LIBLZ4" = "yes" && test -x "$PKG_CONFIG" && $PKG_CONFIG --exists liblz4; then
AC_MSG_CHECKING(for liblz4 using pkg-config)
LIBLZ4_VER=`$PKG_CONFIG liblz4 --modversion`
LIBLZ4_INC=`$PKG_CONFIG liblz4 --cflags`
LIBLZ4_LIB=`$PKG_CONFIG liblz4 --libs`
AC_MSG_RESULT(found version $LIBLZ4_VER)
PHP_EVAL_LIBLINE($LIBLZ4_LIB, REDIS_SHARED_LIBADD)
PHP_EVAL_INCLINE($LIBLZ4_INC)
elif test "$PHP_LIBLZ4" != "no"; then
AC_MSG_CHECKING(for liblz4 files in default path)
for i in $PHP_LIBLZ4 /usr/local /usr; do
if test -r $i/include/lz4.h; then
AC_MSG_RESULT(found in $i)
LIBLZ4_DIR=$i
break
fi
done
if test -z "$LIBLZ4_DIR"; then
AC_MSG_RESULT([not found])
AC_MSG_ERROR([Please reinstall the liblz4 distribution])
fi
PHP_CHECK_LIBRARY(lz4, LZ4_compress,
[
PHP_ADD_LIBRARY_WITH_PATH(lz4, $LIBLZ4_DIR/$PHP_LIBDIR, REDIS_SHARED_LIBADD)
], [
AC_MSG_ERROR([could not find usable liblz4])
], [
-L$LIBLZ4_DIR/$PHP_LIBDIR
])
PHP_SUBST(REDIS_SHARED_LIBADD)
else
AC_MSG_ERROR([only system liblz4 is supported])
fi
fi
if test "$PHP_REDIS_ZSTD" != "no"; then
AC_DEFINE(HAVE_REDIS_ZSTD, 1, [ ])
if test "$PHP_LIBZSTD" = "yes" && test -x "$PKG_CONFIG" && $PKG_CONFIG --exists libzstd; then
AC_MSG_CHECKING(for libzstd using pkg-config)
LIBZSTD_VER=`$PKG_CONFIG libzstd --modversion`
if $PKG_CONFIG libzstd --atleast-version 1.3.0; then
LIBZSTD_INC=`$PKG_CONFIG libzstd --cflags`
LIBZSTD_LIB=`$PKG_CONFIG libzstd --libs`
AC_MSG_RESULT(found version $LIBZSTD_VER)
PHP_EVAL_LIBLINE($LIBZSTD_LIB, REDIS_SHARED_LIBADD)
PHP_EVAL_INCLINE($LIBZSTD_INC)
else
AC_MSG_ERROR([found version $LIBZSTD_VER, version 1.3.0 required])
fi
elif test "$PHP_LIBZSTD" != "no"; then
AC_MSG_CHECKING(for libzstd files in default path)
for i in $PHP_LIBZSTD /usr/local /usr; do
if test -r $i/include/zstd.h; then
AC_MSG_RESULT(found in $i)
LIBZSTD_DIR=$i
break
fi
done
if test -z "$LIBZSTD_DIR"; then
AC_MSG_RESULT([not found])
AC_MSG_ERROR([Please reinstall the libzstd distribution])
fi
PHP_CHECK_LIBRARY(zstd, ZSTD_getFrameContentSize,
[
PHP_ADD_LIBRARY_WITH_PATH(zstd, $LIBZSTD_DIR/$PHP_LIBDIR, REDIS_SHARED_LIBADD)
], [
AC_MSG_ERROR([could not find usable libzstd, version 1.3.0 required])
], [
-L$LIBZSTD_DIR/$PHP_LIBDIR
])
else
AC_MSG_ERROR([only system libzstd is supported])
fi
fi
AC_CHECK_PROG([GIT], [git], [yes], [no])
if test "$GIT" = "yes" && test -d "$srcdir/.git"; then
AC_DEFINE_UNQUOTED(GIT_REVISION, ["$(git log -1 --format=%H)"], [ ])
fi
PHP_SUBST(REDIS_SHARED_LIBADD)
PHP_NEW_EXTENSION(redis, redis.c redis_commands.c library.c redis_session.c redis_array.c redis_array_impl.c redis_cluster.c cluster_library.c redis_sentinel.c sentinel_library.c backoff.c $lzf_sources, $ext_shared)
fi
redis-6.0.2/config.w32 0000644 0001750 0000012 00000001711 14515245367 015222 0 ustar pyatsukhnenko wheel // vim: ft=javascript:
ARG_ENABLE("redis", "whether to enable redis support", "no");
ARG_ENABLE("redis-session", "whether to enable sessions", "yes");
ARG_ENABLE("redis-igbinary", "whether to enable igbinary serializer support", "no");
if (PHP_REDIS != "no") {
var sources = "redis.c redis_commands.c library.c redis_session.c redis_array.c redis_array_impl.c redis_cluster.c cluster_library.c redis_sentinel.c sentinel_library.c backoff.c";
if (PHP_REDIS_SESSION != "no") {
ADD_EXTENSION_DEP("redis", "session");
ADD_FLAG("CFLAGS_REDIS", ' /D PHP_SESSION=1 ');
AC_DEFINE("HAVE_REDIS_SESSION", 1);
}
if (PHP_REDIS_IGBINARY != "no") {
if (CHECK_HEADER_ADD_INCLUDE("igbinary.h", "CFLAGS_REDIS", configure_module_dirname + "\\..\\igbinary")) {
ADD_EXTENSION_DEP("redis", "igbinary");
AC_DEFINE("HAVE_REDIS_IGBINARY", 1);
} else {
WARNING("redis igbinary support not enabled");
}
}
EXTENSION("redis", sources);
}
redis-6.0.2/crc16.h 0000644 0001750 0000012 00000010603 14515245367 014507 0 ustar pyatsukhnenko wheel /*
* Copyright 2001-2010 Georges Menie (www.menie.org)
* Copyright 2010 Salvatore Sanfilippo (adapted to Redis coding style)
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University of California, Berkeley nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* CRC16 implementation according to CCITT standards.
*
* Note by @antirez: this is actually the XMODEM CRC 16 algorithm, using the
* following parameters:
*
* Name : "XMODEM", also known as "ZMODEM", "CRC-16/ACORN"
* Width : 16 bit
* Poly : 1021 (That is actually x^16 + x^12 + x^5 + 1)
* Initialization : 0000
* Reflect Input byte : False
* Reflect Output CRC : False
* Xor constant to output CRC : 0000
* Output for "123456789" : 31C3
*/
#include
static const uint16_t crc16tab[256]= {
0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
};
static inline uint16_t crc16(const char *buf, int len) {
int counter;
uint16_t crc = 0;
for (counter = 0; counter < len; counter++)
crc = (crc<<8) ^ crc16tab[((crc>>8) ^ *buf++)&0x00FF];
return crc;
}
redis-6.0.2/library.c 0000644 0001750 0000012 00000410332 14515245367 015233 0 ustar pyatsukhnenko wheel #include "php_redis.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "common.h"
#include "php_network.h"
#include
#ifdef HAVE_REDIS_IGBINARY
#include "igbinary/igbinary.h"
#endif
#ifdef HAVE_REDIS_MSGPACK
#include "msgpack/php_msgpack.h"
#endif
#ifdef HAVE_REDIS_LZF
#include
#ifndef LZF_MARGIN
#define LZF_MARGIN 128
#endif
#endif
#ifdef HAVE_REDIS_ZSTD
#include
#endif
#ifdef HAVE_REDIS_LZ4
#include
#include
/* uint8_t crf + int length */
#define REDIS_LZ4_HDR_SIZE (sizeof(uint8_t) + sizeof(int))
#if defined(LZ4HC_CLEVEL_MAX)
/* version >= 1.7.5 */
#define REDIS_LZ4_MAX_CLEVEL LZ4HC_CLEVEL_MAX
#elif defined (LZ4HC_MAX_CLEVEL)
/* version >= 1.7.3 */
#define REDIS_LZ4_MAX_CLEVEL LZ4HC_MAX_CLEVEL
#else
/* older versions */
#define REDIS_LZ4_MAX_CLEVEL 12
#endif
#endif
#include
#include "php_redis.h"
#include "library.h"
#include "redis_commands.h"
#ifdef HAVE_REDIS_JSON
#include
#endif
#include
#include
#define UNSERIALIZE_NONE 0
#define UNSERIALIZE_KEYS 1
#define UNSERIALIZE_VALS 2
#define UNSERIALIZE_ALL 3
#define SCORE_DECODE_NONE 0
#define SCORE_DECODE_INT 1
#define SCORE_DECODE_DOUBLE 2
/* PhpRedis often returns either FALSE or NULL depending on whether we have
* an option set, so this macro just wraps that often repeated logic */
#define REDIS_ZVAL_NULL(sock_, zv_) \
do { \
if ((sock_)->null_mbulk_as_null) { \
ZVAL_NULL((zv_)); \
} else { \
ZVAL_FALSE((zv_)); \
} \
} while (0)
#ifndef PHP_WIN32
#include /* TCP_NODELAY */
#include /* SO_KEEPALIVE */
#else
#include
#endif
extern zend_class_entry *redis_ce;
extern zend_class_entry *redis_exception_ce;
extern int le_redis_pconnect;
static int redis_mbulk_reply_zipped_raw_variant(RedisSock *redis_sock, zval *zret, int count);
/* Register a persistent resource in a a way that works for every PHP 7 version. */
void redis_register_persistent_resource(zend_string *id, void *ptr, int le_id) {
#if PHP_VERSION_ID < 70300
zend_resource res;
res.type = le_id;
res.ptr = ptr;
zend_hash_str_update_mem(&EG(persistent_list), ZSTR_VAL(id), ZSTR_LEN(id), &res, sizeof(res));
#else
zend_register_persistent_resource(ZSTR_VAL(id), ZSTR_LEN(id), ptr, le_id);
#endif
}
static ConnectionPool *
redis_sock_get_connection_pool(RedisSock *redis_sock)
{
ConnectionPool *pool;
zend_resource *le;
zend_string *persistent_id;
/* Generate our unique pool id depending on configuration */
persistent_id = redis_pool_spprintf(redis_sock, INI_STR("redis.pconnect.pool_pattern"));
/* Return early if we can find the pool */
if ((le = zend_hash_find_ptr(&EG(persistent_list), persistent_id))) {
zend_string_release(persistent_id);
return le->ptr;
}
/* Create the pool and store it in our persistent list */
pool = pecalloc(1, sizeof(*pool), 1);
zend_llist_init(&pool->list, sizeof(php_stream *), NULL, 1);
redis_register_persistent_resource(persistent_id, pool, le_redis_pconnect);
zend_string_release(persistent_id);
return pool;
}
/* Helper to reselect the proper DB number when we reconnect */
static int reselect_db(RedisSock *redis_sock) {
char *cmd, *response;
int cmd_len, response_len;
cmd_len = redis_spprintf(redis_sock, NULL, &cmd, "SELECT", "d",
redis_sock->dbNumber);
if (redis_sock_write(redis_sock, cmd, cmd_len) < 0) {
efree(cmd);
return -1;
}
efree(cmd);
if ((response = redis_sock_read(redis_sock, &response_len)) == NULL) {
return -1;
}
if (strncmp(response, "+OK", 3)) {
efree(response);
return -1;
}
efree(response);
return 0;
}
/* Append an AUTH command to a smart string if neccessary. This will either
* append the new style AUTH , old style AUTH , or
* append no command at all. Function returns 1 if we appended a command
* and 0 otherwise. */
static int redis_sock_append_auth(RedisSock *redis_sock, smart_string *str) {
/* We need a password at least */
if (redis_sock->pass == NULL)
return 0;
REDIS_CMD_INIT_SSTR_STATIC(str, !!redis_sock->user + !!redis_sock->pass, "AUTH");
if (redis_sock->user)
redis_cmd_append_sstr_zstr(str, redis_sock->user);
redis_cmd_append_sstr_zstr(str, redis_sock->pass);
/* We appended a command */
return 1;
}
PHP_REDIS_API void
redis_sock_set_auth(RedisSock *redis_sock, zend_string *user, zend_string *pass)
{
/* Release existing user/pass */
redis_sock_free_auth(redis_sock);
/* Set new user/pass */
redis_sock->user = user ? zend_string_copy(user) : NULL;
redis_sock->pass = pass ? zend_string_copy(pass) : NULL;
}
PHP_REDIS_API void
redis_sock_set_auth_zval(RedisSock *redis_sock, zval *zv) {
zend_string *user, *pass;
if (redis_extract_auth_info(zv, &user, &pass) == FAILURE)
return;
redis_sock_set_auth(redis_sock, user, pass);
if (user) zend_string_release(user);
if (pass) zend_string_release(pass);
}
PHP_REDIS_API void
redis_sock_free_auth(RedisSock *redis_sock) {
if (redis_sock->user) {
zend_string_release(redis_sock->user);
redis_sock->user = NULL;
}
if (redis_sock->pass) {
zend_string_release(redis_sock->pass);
redis_sock->pass = NULL;
}
}
PHP_REDIS_API char *
redis_sock_auth_cmd(RedisSock *redis_sock, int *cmdlen) {
char *cmd;
/* AUTH requires at least a password */
if (redis_sock->pass == NULL)
return NULL;
if (redis_sock->user) {
*cmdlen = redis_spprintf(redis_sock, NULL, &cmd, "AUTH", "SS", redis_sock->user, redis_sock->pass);
} else {
*cmdlen = redis_spprintf(redis_sock, NULL, &cmd, "AUTH", "S", redis_sock->pass);
}
return cmd;
}
/* Send Redis AUTH and process response */
PHP_REDIS_API int redis_sock_auth(RedisSock *redis_sock) {
char *cmd, inbuf[4096];
int cmdlen;
size_t len;
if ((cmd = redis_sock_auth_cmd(redis_sock, &cmdlen)) == NULL)
return SUCCESS;
if (redis_sock_write(redis_sock, cmd, cmdlen) < 0) {
efree(cmd);
return FAILURE;
}
efree(cmd);
if (redis_sock_gets(redis_sock, inbuf, sizeof(inbuf) - 1, &len) < 0 || strncmp(inbuf, "+OK", 3)) {
return FAILURE;
}
return SUCCESS;
}
/* Helper function and macro to test a RedisSock error prefix. */
#define REDIS_SOCK_ERRCMP_STATIC(rs, s) redis_sock_errcmp(rs, s, sizeof(s)-1)
static int redis_sock_errcmp(RedisSock *redis_sock, const char *err, size_t errlen) {
return ZSTR_LEN(redis_sock->err) >= errlen &&
memcmp(ZSTR_VAL(redis_sock->err), err, errlen) == 0;
}
/* Helper function that will throw an exception for a small number of ERR codes
* returned by Redis. Typically we just return FALSE to the caller in the event
* of an ERROR reply, but for the following error types:
* 1) MASTERDOWN
* 2) AUTH
* 3) LOADING
*/
static void
redis_error_throw(RedisSock *redis_sock)
{
/* Short circuit if we have no redis_sock or any error */
if (redis_sock == NULL || redis_sock->err == NULL)
return;
/* Redis 6 decided to add 'ERR AUTH' which has a normal 'ERR' prefix
* but is actually an authentication error that we will want to throw
* an exception for, so just short circuit if this is any other 'ERR'
* prefixed error. */
if (REDIS_SOCK_ERRCMP_STATIC(redis_sock, "ERR") &&
!REDIS_SOCK_ERRCMP_STATIC(redis_sock, "ERR AUTH")) return;
/* We may want to flip this logic and check for MASTERDOWN, AUTH,
* and LOADING but that may have side effects (esp for things like
* Disque) */
if (!REDIS_SOCK_ERRCMP_STATIC(redis_sock, "NOSCRIPT") &&
!REDIS_SOCK_ERRCMP_STATIC(redis_sock, "NOQUORUM") &&
!REDIS_SOCK_ERRCMP_STATIC(redis_sock, "NOGOODSLAVE") &&
!REDIS_SOCK_ERRCMP_STATIC(redis_sock, "WRONGTYPE") &&
!REDIS_SOCK_ERRCMP_STATIC(redis_sock, "BUSYGROUP") &&
!REDIS_SOCK_ERRCMP_STATIC(redis_sock, "NOGROUP"))
{
REDIS_THROW_EXCEPTION(ZSTR_VAL(redis_sock->err), 0);
}
}
static int
read_mbulk_header(RedisSock *redis_sock, int *nelem)
{
char line[4096];
size_t len;
/* Throws exception on failure */
if (redis_sock_gets(redis_sock, line, sizeof(line) - 1, &len) < 0) {
return FAILURE;
}
if (*line != TYPE_MULTIBULK) {
if (*line == TYPE_ERR) {
redis_sock_set_err(redis_sock, line + 1, len - 1);
}
return FAILURE;
}
*nelem = atoi(line + 1);
return SUCCESS;
}
PHP_REDIS_API int
redis_check_eof(RedisSock *redis_sock, zend_bool no_retry, zend_bool no_throw)
{
unsigned int retry_index;
char *errmsg;
if (!redis_sock || !redis_sock->stream || redis_sock->status == REDIS_SOCK_STATUS_FAILED) {
if (!no_throw) {
REDIS_THROW_EXCEPTION( "Connection closed", 0);
}
return -1;
}
/* NOITCE: set errno = 0 here
*
* There is a bug in php socket stream to check liveness of a connection:
* if (0 >= recv(sock->socket, &buf, sizeof(buf), MSG_PEEK) && php_socket_errno() != EWOULDBLOCK) {
* alive = 0;
* }
* If last errno is EWOULDBLOCK and recv returns 0 because of connection closed, alive would not be
* set to 0. However, the connection is close indeed. The php_stream_eof is not reliable. This will
* cause a "read error on connection" exception when use a closed persistent connection.
*
* We work around this by set errno = 0 first.
*
* Bug fix of php: https://github.com/php/php-src/pull/1456
* */
errno = 0;
if (php_stream_eof(redis_sock->stream) == 0) {
/* Success */
return 0;
} else if (redis_sock->mode == MULTI || redis_sock->watching) {
errmsg = "Connection lost and socket is in MULTI/watching mode";
} else {
errmsg = "Connection lost";
redis_backoff_reset(&redis_sock->backoff);
for (retry_index = 0; !no_retry && retry_index < redis_sock->max_retries; ++retry_index) {
/* close existing stream before reconnecting */
if (redis_sock->stream) {
/* reconnect no need to reset mode, it will cause pipeline mode socket exception */
redis_sock_disconnect(redis_sock, 1, 0);
}
/* Sleep based on our backoff algorithm */
zend_ulong delay = redis_backoff_compute(&redis_sock->backoff, retry_index);
if (delay != 0)
usleep(delay);
/* reconnect */
if (redis_sock_connect(redis_sock) == 0) {
/* check for EOF again. */
errno = 0;
if (php_stream_eof(redis_sock->stream) == 0) {
if (redis_sock_auth(redis_sock) != SUCCESS) {
errmsg = "AUTH failed while reconnecting";
break;
}
redis_sock->status = REDIS_SOCK_STATUS_AUTHENTICATED;
/* If we're using a non-zero db, reselect it */
if (redis_sock->dbNumber && reselect_db(redis_sock) != 0) {
errmsg = "SELECT failed while reconnecting";
break;
}
redis_sock->status = REDIS_SOCK_STATUS_READY;
/* Success */
return 0;
}
}
}
}
/* close stream and mark socket as failed */
redis_sock_disconnect(redis_sock, 1, 1);
redis_sock->status = REDIS_SOCK_STATUS_FAILED;
if (!no_throw) {
REDIS_THROW_EXCEPTION( errmsg, 0);
}
return -1;
}
PHP_REDIS_API int
redis_sock_read_scan_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
REDIS_SCAN_TYPE type, zend_long *iter)
{
REDIS_REPLY_TYPE reply_type;
long reply_info;
char err[4096], *p_iter;
size_t errlen;
/* Our response should have two multibulk replies */
if(redis_read_reply_type(redis_sock, &reply_type, &reply_info)<0
|| reply_type != TYPE_MULTIBULK || reply_info != 2)
{
if (reply_type == TYPE_ERR) {
if (redis_sock_gets(redis_sock, err, sizeof(err), &errlen) == 0) {
redis_sock_set_err(redis_sock, err, errlen);
}
}
return -1;
}
/* The BULK response iterator */
if(redis_read_reply_type(redis_sock, &reply_type, &reply_info)<0
|| reply_type != TYPE_BULK)
{
return -1;
}
/* Attempt to read the iterator */
if(!(p_iter = redis_sock_read_bulk_reply(redis_sock, reply_info))) {
return -1;
}
/* Push the iterator out to the caller */
*iter = atol(p_iter);
efree(p_iter);
/* Read our actual keys/members/etc differently depending on what kind of
scan command this is. They all come back in slightly different ways */
switch(type) {
case TYPE_SCAN:
return redis_mbulk_reply_raw(INTERNAL_FUNCTION_PARAM_PASSTHRU,
redis_sock, NULL, NULL);
case TYPE_SSCAN:
return redis_sock_read_multibulk_reply(
INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL, NULL);
case TYPE_ZSCAN:
return redis_mbulk_reply_zipped_keys_dbl(INTERNAL_FUNCTION_PARAM_PASSTHRU,
redis_sock, NULL, NULL);
case TYPE_HSCAN:
return redis_mbulk_reply_zipped_vals(INTERNAL_FUNCTION_PARAM_PASSTHRU,
redis_sock, NULL, NULL);
default:
return -1;
}
}
PHP_REDIS_API int
redis_pubsub_response(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, zval *z_tab, void *ctx)
{
if (ctx == NULL) {
return redis_long_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR) {
return redis_read_variant_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR + 1) {
return redis_mbulk_reply_zipped_keys_int(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else {
ZEND_ASSERT(!"memory corruption?");
return FAILURE;
}
}
static void
ht_free_subs(zval *data)
{
efree(Z_PTR_P(data));
}
PHP_REDIS_API int redis_subscribe_response(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, zval *z_tab,
void *ctx)
{
HashTable *subs;
subscribeCallback *cb;
subscribeContext *sctx = (subscribeContext*)ctx;
zval *z_tmp, z_resp;
int i;
ALLOC_HASHTABLE(subs);
zend_hash_init(subs, 0, NULL, ht_free_subs, 0);
// Consume response(s) from subscribe, which will vary on argc
while(sctx->argc--) {
ZVAL_NULL(&z_resp);
if (!redis_sock_read_multibulk_reply_zval(redis_sock, &z_resp)) {
goto error;
}
// We'll need to find the command response
if ((z_tmp = zend_hash_index_find(Z_ARRVAL(z_resp), 0)) == NULL) {
goto error;
}
// Make sure the command response matches the command we called
if(strcasecmp(Z_STRVAL_P(z_tmp), sctx->kw) !=0) {
goto error;
}
if ((z_tmp = zend_hash_index_find(Z_ARRVAL(z_resp), 1)) == NULL) {
goto error;
}
zend_hash_str_update_mem(subs, Z_STRVAL_P(z_tmp), Z_STRLEN_P(z_tmp),
&sctx->cb, sizeof(sctx->cb));
zval_dtor(&z_resp);
}
if (strcasecmp(sctx->kw, "ssubscribe") == 0) {
i = REDIS_SSUBSCRIBE_IDX;
} else if (strcasecmp(sctx->kw, "psubscribe") == 0) {
i = REDIS_PSUBSCRIBE_IDX;
} else {
i = REDIS_SUBSCRIBE_IDX;
}
efree(sctx);
if (redis_sock->subs[i]) {
zend_string *zkey;
ZEND_HASH_FOREACH_STR_KEY_PTR(subs, zkey, cb) {
zend_hash_update_mem(redis_sock->subs[i], zkey, cb, sizeof(*cb));
} ZEND_HASH_FOREACH_END();
zend_hash_destroy(subs);
efree(subs);
RETVAL_TRUE;
return SUCCESS;
}
redis_sock->subs[i] = subs;
/* Multibulk response, {[pattern], type, channel, payload } */
while (redis_sock->subs[i]) {
zval z_ret, z_args[4], *z_type, *z_chan, *z_pat = NULL, *z_data;
int tab_idx = 1, is_pmsg = 0;
HashTable *ht_tab;
zend_string *zs;
ZVAL_NULL(&z_resp);
if (!redis_sock_read_multibulk_reply_zval(redis_sock, &z_resp)) {
goto failure;
}
ht_tab = Z_ARRVAL(z_resp);
if ((z_type = zend_hash_index_find(ht_tab, 0)) == NULL ||
Z_TYPE_P(z_type) != IS_STRING
) {
goto failure;
}
// Check for message or pmessage
if (zend_string_equals_literal_ci(Z_STR_P(z_type), "message") ||
zend_string_equals_literal_ci(Z_STR_P(z_type), "pmessage") ||
zend_string_equals_literal_ci(Z_STR_P(z_type), "smessage")
) {
is_pmsg = *Z_STRVAL_P(z_type)=='p';
} else {
zval_dtor(&z_resp);
continue;
}
// Extract pattern if it's a pmessage
if (is_pmsg) {
z_pat = zend_hash_index_find(ht_tab, tab_idx++);
if (z_pat == NULL || Z_TYPE_P(z_pat) != IS_STRING)
goto failure;
}
/* Extract channel */
z_chan = zend_hash_index_find(ht_tab, tab_idx++);
if (z_chan == NULL || Z_TYPE_P(z_chan) != IS_STRING)
goto failure;
/* Finally, extract data */
z_data = zend_hash_index_find(ht_tab, tab_idx++);
if (z_data == NULL)
goto failure;
/* Find our callback, either by channel or pattern string */
zs = z_pat != NULL ? Z_STR_P(z_pat) : Z_STR_P(z_chan);
if ((cb = zend_hash_find_ptr(redis_sock->subs[i], zs)) == NULL)
goto failure;
// Different args for SUBSCRIBE and PSUBSCRIBE
z_args[0] = *getThis();
if(is_pmsg) {
z_args[1] = *z_pat;
z_args[2] = *z_chan;
z_args[3] = *z_data;
} else {
z_args[1] = *z_chan;
z_args[2] = *z_data;
}
// Set arg count
cb->fci.param_count = tab_idx;
cb->fci.retval = &z_ret;
cb->fci.params = z_args;
// Execute callback
if (zend_call_function(&cb->fci, &cb->fci_cache) != SUCCESS) {
goto failure;
}
// If we have a return value free it
zval_ptr_dtor(&z_ret);
zval_dtor(&z_resp);
}
RETVAL_TRUE;
return SUCCESS;
// This is an error state, clean up
error:
efree(sctx);
zend_hash_destroy(subs);
efree(subs);
failure:
zval_dtor(&z_resp);
RETVAL_FALSE;
return FAILURE;
}
PHP_REDIS_API int redis_unsubscribe_response(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, zval *z_tab,
void *ctx)
{
subscribeContext *sctx = (subscribeContext*)ctx;
zval *z_chan, z_ret, z_resp;
int i;
if (strcasecmp(sctx->kw, "sunsubscribe") == 0) {
i = REDIS_SSUBSCRIBE_IDX;
} else if (strcasecmp(sctx->kw, "punsubscribe") == 0) {
i = REDIS_PSUBSCRIBE_IDX;
} else {
i = REDIS_SUBSCRIBE_IDX;
}
if (!sctx->argc && redis_sock->subs[i]) {
sctx->argc = zend_hash_num_elements(redis_sock->subs[i]);
}
array_init(&z_ret);
while (sctx->argc--) {
ZVAL_NULL(&z_resp);
if (!redis_sock_read_multibulk_reply_zval(redis_sock, &z_resp) ||
(z_chan = zend_hash_index_find(Z_ARRVAL(z_resp), 1)) == NULL
) {
efree(sctx);
zval_dtor(&z_resp);
zval_dtor(&z_ret);
RETVAL_FALSE;
return FAILURE;
}
if (!redis_sock->subs[i] ||
!zend_hash_str_exists(redis_sock->subs[i], Z_STRVAL_P(z_chan), Z_STRLEN_P(z_chan))
) {
add_assoc_bool_ex(&z_ret, Z_STRVAL_P(z_chan), Z_STRLEN_P(z_chan), 0);
} else {
zend_hash_str_del(redis_sock->subs[i], Z_STRVAL_P(z_chan), Z_STRLEN_P(z_chan));
add_assoc_bool_ex(&z_ret, Z_STRVAL_P(z_chan), Z_STRLEN_P(z_chan), 1);
}
zval_dtor(&z_resp);
}
efree(sctx);
if (redis_sock->subs[i] && !zend_hash_num_elements(redis_sock->subs[i])) {
zend_hash_destroy(redis_sock->subs[i]);
efree(redis_sock->subs[i]);
redis_sock->subs[i] = NULL;
}
RETVAL_ZVAL(&z_ret, 0, 1);
return SUCCESS;
}
PHP_REDIS_API zval *
redis_sock_read_multibulk_reply_zval(RedisSock *redis_sock, zval *z_tab)
{
int numElems;
if (read_mbulk_header(redis_sock, &numElems) < 0) {
ZVAL_NULL(z_tab);
return NULL;
}
array_init(z_tab);
redis_mbulk_reply_loop(redis_sock, z_tab, numElems, UNSERIALIZE_ALL);
return z_tab;
}
/**
* redis_sock_read_bulk_reply
*/
PHP_REDIS_API char *
redis_sock_read_bulk_reply(RedisSock *redis_sock, int bytes)
{
int offset = 0, nbytes;
char *reply;
ssize_t got;
if (-1 == bytes || -1 == redis_check_eof(redis_sock, 1, 0)) {
return NULL;
}
/* + 2 for \r\n */
nbytes = bytes + 2;
/* Allocate memory for string */
reply = emalloc(nbytes);
/* Consume bulk string */
while (offset < nbytes) {
got = redis_sock_read_raw(redis_sock, reply + offset, nbytes - offset);
if (got < 0 || (got == 0 && php_stream_eof(redis_sock->stream)))
break;
offset += got;
}
/* Protect against reading too few bytes */
if (offset < nbytes) {
/* Error or EOF */
REDIS_THROW_EXCEPTION("socket error on read socket", 0);
efree(reply);
return NULL;
}
/* Null terminate reply string */
reply[bytes] = '\0';
return reply;
}
/**
* redis_sock_read
*/
PHP_REDIS_API char *
redis_sock_read(RedisSock *redis_sock, int *buf_len)
{
char inbuf[4096];
size_t len;
*buf_len = 0;
if (redis_sock_gets(redis_sock, inbuf, sizeof(inbuf) - 1, &len) < 0) {
return NULL;
}
switch(inbuf[0]) {
case '-':
redis_sock_set_err(redis_sock, inbuf+1, len);
/* Filter our ERROR through the few that should actually throw */
redis_error_throw(redis_sock);
return NULL;
case '$':
*buf_len = atoi(inbuf + 1);
return redis_sock_read_bulk_reply(redis_sock, *buf_len);
case '*':
/* For null multi-bulk replies (like timeouts from brpoplpush): */
if(memcmp(inbuf + 1, "-1", 2) == 0) {
return NULL;
}
REDIS_FALLTHROUGH;
case '+':
case ':':
/* Single Line Reply */
/* +OK or :123 */
if (len > 1) {
*buf_len = len;
return estrndup(inbuf, *buf_len);
}
REDIS_FALLTHROUGH;
default:
zend_throw_exception_ex(redis_exception_ce, 0,
"protocol error, got '%c' as reply type byte\n",
inbuf[0]
);
}
return NULL;
}
/* A simple union to store the various arg types we might handle in our
* redis_spprintf command formatting function */
union resparg {
char *str;
zend_string *zstr;
zval *zv;
int ival;
long lval;
double dval;
};
static zend_string *redis_hash_auth(zend_string *user, zend_string *pass) {
zend_string *algo, *hex;
smart_str salted = {0};
const php_hash_ops *ops;
unsigned char *digest;
void *ctx;
/* No op if there is not username/password */
if (user == NULL && pass == NULL)
return NULL;
/* Theoretically inpossible but check anyway */
algo = zend_string_init("sha256", sizeof("sha256") - 1, 0);
if ((ops = redis_hash_fetch_ops(algo)) == NULL) {
zend_string_release(algo);
return NULL;
}
/* Hash username + password with our salt global */
smart_str_alloc(&salted, 256, 0);
if (user) smart_str_append_ex(&salted, user, 0);
if (pass) smart_str_append_ex(&salted, pass, 0);
smart_str_appendl_ex(&salted, REDIS_G(salt), sizeof(REDIS_G(salt)), 0);
ctx = emalloc(ops->context_size);
#if PHP_VERSION_ID >= 80100
ops->hash_init(ctx,NULL);
#else
ops->hash_init(ctx);
#endif
ops->hash_update(ctx, (const unsigned char *)ZSTR_VAL(salted.s), ZSTR_LEN(salted.s));
digest = emalloc(ops->digest_size);
ops->hash_final(digest, ctx);
efree(ctx);
hex = zend_string_safe_alloc(ops->digest_size, 2, 0, 0);
php_hash_bin2hex(ZSTR_VAL(hex), digest, ops->digest_size);
ZSTR_VAL(hex)[2 * ops->digest_size] = 0;
efree(digest);
zend_string_release(algo);
smart_str_free(&salted);
return hex;
}
static void append_auth_hash(smart_str *dst, zend_string *user, zend_string *pass) {
zend_string *s;
if ((s = redis_hash_auth(user, pass)) != NULL) {
smart_str_appendc(dst, ':');
smart_str_append_ex(dst, s, 0);
zend_string_release(s);
}
}
/* A printf like function to generate our connection pool hash value. */
PHP_REDIS_API zend_string *
redis_pool_spprintf(RedisSock *redis_sock, char *fmt, ...) {
smart_str str = {0};
smart_str_alloc(&str, 128, 0);
/* We always include phpredis_: */
smart_str_appendl(&str, "phpredis_", sizeof("phpredis_") - 1);
smart_str_append_ex(&str, redis_sock->host, 0);
smart_str_appendc(&str, ':');
smart_str_append_long(&str, (zend_long)redis_sock->port);
/* Short circuit if we don't have a pattern */
if (fmt == NULL) {
smart_str_0(&str);
return str.s;
}
while (*fmt) {
switch (*fmt) {
case 'i':
if (redis_sock->persistent_id) {
smart_str_appendc(&str, ':');
smart_str_append_ex(&str, redis_sock->persistent_id, 0);
}
break;
case 'u':
smart_str_appendc(&str, ':');
if (redis_sock->user) {
smart_str_append_ex(&str, redis_sock->user, 0);
}
break;
case 'p':
append_auth_hash(&str, NULL, redis_sock->pass);
break;
case 'a':
append_auth_hash(&str, redis_sock->user, redis_sock->pass);
break;
default:
/* Maybe issue a php_error_docref? */
break;
}
fmt++;
}
smart_str_0(&str);
return str.s;
}
/* A printf like method to construct a Redis RESP command. It has been extended
* to take a few different format specifiers that are convenient to phpredis.
*
* s - C string followed by length as a
* S - Pointer to a zend_string
* k - Same as 's' but the value will be prefixed if phpredis is set up do do
* that and the working slot will be set if it has been passed.
* v - A z_val which will be serialized if phpredis is configured to serialize.
* f - A double value
* F - Alias to 'f'
* i - An integer
* d - Alias to 'i'
* l - A long
* L - Alias to 'l'
*/
PHP_REDIS_API int
redis_spprintf(RedisSock *redis_sock, short *slot, char **ret, char *kw, char *fmt, ...) {
smart_string cmd = {0};
va_list ap;
union resparg arg;
char *dup;
int argfree;
size_t arglen;
va_start(ap, fmt);
/* Header */
redis_cmd_init_sstr(&cmd, strlen(fmt), kw, strlen(kw));
while (*fmt) {
switch (*fmt) {
case 's':
arg.str = va_arg(ap, char*);
arglen = va_arg(ap, size_t);
redis_cmd_append_sstr(&cmd, arg.str, arglen);
break;
case 'S':
arg.zstr = va_arg(ap, zend_string*);
redis_cmd_append_sstr(&cmd, ZSTR_VAL(arg.zstr), ZSTR_LEN(arg.zstr));
break;
case 'k':
arg.str = va_arg(ap, char*);
arglen = va_arg(ap, size_t);
argfree = redis_key_prefix(redis_sock, &arg.str, &arglen);
redis_cmd_append_sstr(&cmd, arg.str, arglen);
if (slot) *slot = cluster_hash_key(arg.str, arglen);
if (argfree) efree(arg.str);
break;
case 'v':
arg.zv = va_arg(ap, zval*);
argfree = redis_pack(redis_sock, arg.zv, &dup, &arglen);
redis_cmd_append_sstr(&cmd, dup, arglen);
if (argfree) efree(dup);
break;
case 'f':
case 'F':
arg.dval = va_arg(ap, double);
redis_cmd_append_sstr_dbl(&cmd, arg.dval);
break;
case 'i':
case 'd':
arg.ival = va_arg(ap, int);
redis_cmd_append_sstr_int(&cmd, arg.ival);
break;
case 'l':
case 'L':
arg.lval = va_arg(ap, long);
redis_cmd_append_sstr_long(&cmd, arg.lval);
break;
}
fmt++;
}
/* varargs cleanup */
va_end(ap);
/* Null terminate */
smart_string_0(&cmd);
/* Push command string, return length */
*ret = cmd.c;
return cmd.len;
}
/*
* Given a smart string, number of arguments, a keyword, and the length of the keyword
* initialize our smart string with the proper Redis header for the command to follow
*/
int redis_cmd_init_sstr(smart_string *str, int num_args, char *keyword, int keyword_len) {
smart_string_appendc(str, '*');
smart_string_append_long(str, num_args + 1);
smart_string_appendl(str, _NL, sizeof(_NL) -1);
smart_string_appendc(str, '$');
smart_string_append_long(str, keyword_len);
smart_string_appendl(str, _NL, sizeof(_NL) - 1);
smart_string_appendl(str, keyword, keyword_len);
smart_string_appendl(str, _NL, sizeof(_NL) - 1);
return str->len;
}
/*
* Append a command sequence to a smart_string
*/
int redis_cmd_append_sstr(smart_string *str, char *append, int append_len) {
smart_string_appendc(str, '$');
smart_string_append_long(str, append_len);
smart_string_appendl(str, _NL, sizeof(_NL) - 1);
smart_string_appendl(str, append, append_len);
smart_string_appendl(str, _NL, sizeof(_NL) - 1);
/* Return our new length */
return str->len;
}
/*
* Append an integer to a smart string command
*/
int redis_cmd_append_sstr_int(smart_string *str, int append) {
char int_buf[32];
int int_len = snprintf(int_buf, sizeof(int_buf), "%d", append);
return redis_cmd_append_sstr(str, int_buf, int_len);
}
/*
* Append a long to a smart string command
*/
int redis_cmd_append_sstr_long(smart_string *str, long append) {
char long_buf[32];
int long_len = snprintf(long_buf, sizeof(long_buf), "%ld", append);
return redis_cmd_append_sstr(str, long_buf, long_len);
}
/*
* Append a 64-bit integer to our command
*/
int redis_cmd_append_sstr_i64(smart_string *str, int64_t append) {
char nbuf[64];
int len = snprintf(nbuf, sizeof(nbuf), "%" PRId64, append);
return redis_cmd_append_sstr(str, nbuf, len);
}
/*
* Append a double to a smart string command
*/
int
redis_cmd_append_sstr_dbl(smart_string *str, double value)
{
char tmp[64], *p;
int len;
/* Convert to string */
len = snprintf(tmp, sizeof(tmp), "%.17g", value);
/* snprintf depends on locale, replace comma with point */
if ((p = strchr(tmp, ',')) != NULL) *p = '.';
// Append the string
return redis_cmd_append_sstr(str, tmp, len);
}
/* Append a zval to a redis command. If redis_sock is passed as non-null we will
* the value may be serialized, if we're configured to do that. */
int redis_cmd_append_sstr_zval(smart_string *str, zval *z, RedisSock *redis_sock) {
int valfree, retval;
zend_string *zstr;
size_t vallen;
char *val;
if (redis_sock != NULL) {
valfree = redis_pack(redis_sock, z, &val, &vallen);
retval = redis_cmd_append_sstr(str, val, vallen);
if (valfree) efree(val);
} else {
zstr = zval_get_string(z);
retval = redis_cmd_append_sstr_zstr(str, zstr);
zend_string_release(zstr);
}
return retval;
}
int redis_cmd_append_sstr_zstr(smart_string *str, zend_string *zstr) {
return redis_cmd_append_sstr(str, ZSTR_VAL(zstr), ZSTR_LEN(zstr));
}
/* Append a string key to a redis command. This function takes care of prefixing the key
* for the caller and setting the slot argument if it is passed non null */
int redis_cmd_append_sstr_key(smart_string *str, char *key, size_t len, RedisSock *redis_sock, short *slot) {
int valfree, retval;
valfree = redis_key_prefix(redis_sock, &key, &len);
if (slot) *slot = cluster_hash_key(key, len);
retval = redis_cmd_append_sstr(str, key, len);
if (valfree) efree(key);
return retval;
}
int redis_cmd_append_sstr_key_zstr(smart_string *dst, zend_string *key, RedisSock *redis_sock, short *slot) {
return redis_cmd_append_sstr_key(dst, ZSTR_VAL(key), ZSTR_LEN(key), redis_sock, slot);
}
int redis_cmd_append_sstr_key_zval(smart_string *dst, zval *zv, RedisSock *redis_sock, short *slot) {
zend_string *key;
int res;
key = zval_get_string(zv);
res = redis_cmd_append_sstr_key_zstr(dst, key, redis_sock, slot);
zend_string_release(key);
return res;
}
int redis_cmd_append_sstr_key_long(smart_string *dst, zend_long lval, RedisSock *redis_sock, short *slot) {
char buf[64];
size_t len;
int res;
len = snprintf(buf, sizeof(buf), ZEND_LONG_FMT, lval);
res = redis_cmd_append_sstr_key(dst, buf, len, redis_sock, slot);
return res;
}
/* Append an array key to a redis smart string command. This function
* handles the boilerplate conditionals around string or integer keys */
int redis_cmd_append_sstr_arrkey(smart_string *cmd, zend_string *kstr, zend_ulong idx)
{
char *arg, kbuf[128];
int len;
if (kstr) {
len = ZSTR_LEN(kstr);
arg = ZSTR_VAL(kstr);
} else {
len = snprintf(kbuf, sizeof(kbuf), "%ld", (long)idx);
arg = (char*)kbuf;
}
return redis_cmd_append_sstr(cmd, arg, len);
}
PHP_REDIS_API int
redis_bulk_double_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) {
char *response;
int response_len;
double ret;
if ((response = redis_sock_read(redis_sock, &response_len)) == NULL) {
if (IS_ATOMIC(redis_sock)) {
RETVAL_FALSE;
} else {
add_next_index_bool(z_tab, 0);
}
return FAILURE;
}
ret = atof(response);
efree(response);
if (IS_ATOMIC(redis_sock)) {
RETVAL_DOUBLE(ret);
} else {
add_next_index_double(z_tab, ret);
}
return SUCCESS;
}
PHP_REDIS_API int redis_type_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) {
char *response;
int response_len;
long l;
if ((response = redis_sock_read(redis_sock, &response_len)) == NULL) {
if (IS_ATOMIC(redis_sock)) {
RETVAL_FALSE;
} else {
add_next_index_bool(z_tab, 0);
}
return FAILURE;
}
if (strncmp(response, "+string", 7) == 0) {
l = REDIS_STRING;
} else if (strncmp(response, "+set", 4) == 0){
l = REDIS_SET;
} else if (strncmp(response, "+list", 5) == 0){
l = REDIS_LIST;
} else if (strncmp(response, "+zset", 5) == 0){
l = REDIS_ZSET;
} else if (strncmp(response, "+hash", 5) == 0){
l = REDIS_HASH;
} else if (strncmp(response, "+stream", 7) == 0) {
l = REDIS_STREAM;
} else {
l = REDIS_NOT_FOUND;
}
efree(response);
if (IS_ATOMIC(redis_sock)) {
RETVAL_LONG(l);
} else {
add_next_index_long(z_tab, l);
}
return SUCCESS;
}
PHP_REDIS_API int
redis_config_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) {
FailableResultCallback cb = ctx;
ZEND_ASSERT(cb == redis_boolean_response || cb == redis_mbulk_reply_zipped_raw);
return cb(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, ctx);
}
PHP_REDIS_API int
redis_zrange_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) {
FailableResultCallback cb;
/* Whether or not we have WITHSCORES */
ZEND_ASSERT(ctx == NULL || ctx == PHPREDIS_CTX_PTR);
cb = ctx ? redis_mbulk_reply_zipped_keys_dbl : redis_sock_read_multibulk_reply;
return cb(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, ctx);
}
PHP_REDIS_API int
redis_srandmember_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) {
FailableResultCallback cb;
/* Whether or not we have a COUNT argument */
ZEND_ASSERT(ctx == NULL || ctx == PHPREDIS_CTX_PTR);
cb = ctx ? redis_sock_read_multibulk_reply : redis_string_response;
return cb(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, ctx);
}
PHP_REDIS_API int redis_info_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) {
char *response;
int response_len;
zval z_ret;
/* Read bulk response */
if ((response = redis_sock_read(redis_sock, &response_len)) == NULL) {
RETVAL_FALSE;
return FAILURE;
}
/* Parse it into a zval array */
ZVAL_UNDEF(&z_ret);
redis_parse_info_response(response, &z_ret);
/* Free source response */
efree(response);
if (IS_ATOMIC(redis_sock)) {
RETVAL_ZVAL(&z_ret, 0, 1);
} else {
add_next_index_zval(z_tab, &z_ret);
}
return SUCCESS;
}
PHP_REDIS_API void
redis_parse_info_response(char *response, zval *z_ret)
{
char *p1, *s1 = NULL;
ZVAL_FALSE(z_ret);
if ((p1 = php_strtok_r(response, _NL, &s1)) != NULL) {
array_init(z_ret);
do {
if (*p1 == '#') continue;
char *p;
zend_uchar type;
zend_long lval;
double dval;
if ((p = strchr(p1, ':')) != NULL) {
type = is_numeric_string(p + 1, strlen(p + 1), &lval, &dval, 0);
switch (type) {
case IS_LONG:
add_assoc_long_ex(z_ret, p1, p - p1, lval);
break;
case IS_DOUBLE:
add_assoc_double_ex(z_ret, p1, p - p1, dval);
break;
default:
add_assoc_string_ex(z_ret, p1, p - p1, p + 1);
}
} else {
add_next_index_string(z_ret, p1);
}
} while ((p1 = php_strtok_r(NULL, _NL, &s1)) != NULL);
}
}
static void
redis_parse_client_info(char *info, zval *z_ret)
{
char *p1, *s1 = NULL;
ZVAL_FALSE(z_ret);
if ((p1 = php_strtok_r(info, " ", &s1)) != NULL) {
array_init(z_ret);
do {
char *p;
zend_uchar type;
zend_long lval;
double dval;
if ((p = strchr(p1, '=')) != NULL) {
type = is_numeric_string(p + 1, strlen(p + 1), &lval, &dval, 0);
switch (type) {
case IS_LONG:
add_assoc_long_ex(z_ret, p1, p - p1, lval);
break;
case IS_DOUBLE:
add_assoc_double_ex(z_ret, p1, p - p1, dval);
break;
default:
add_assoc_string_ex(z_ret, p1, p - p1, p + 1);
}
} else {
add_next_index_string(z_ret, p1);
}
} while ((p1 = php_strtok_r(NULL, " ", &s1)) != NULL);
}
}
static int
redis_client_info_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx)
{
char *resp;
int resp_len;
zval z_ret;
/* Make sure we can read the bulk response from Redis */
if ((resp = redis_sock_read(redis_sock, &resp_len)) == NULL) {
RETVAL_FALSE;
return FAILURE;
}
/* Parse it out */
redis_parse_client_info(resp, &z_ret);
/* Free our response */
efree(resp);
/* Return or append depending if we're atomic */
if (IS_ATOMIC(redis_sock)) {
RETVAL_ZVAL(&z_ret, 0, 1);
} else {
add_next_index_zval(z_tab, &z_ret);
}
return SUCCESS;
}
/*
* Specialized handling of the CLIENT LIST output so it comes out in a simple way for PHP userland code
* to handle.
*/
PHP_REDIS_API int
redis_client_list_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) {
char *resp;
int resp_len;
zval z_ret;
/* Make sure we can read the bulk response from Redis */
if ((resp = redis_sock_read(redis_sock, &resp_len)) == NULL) {
RETVAL_FALSE;
return FAILURE;
} else if (resp_len > 0) {
/* Parse it out */
redis_parse_client_list_response(resp, &z_ret);
} else {
array_init(&z_ret);
}
/* Free our response */
efree(resp);
/* Return or append depending if we're atomic */
if (IS_ATOMIC(redis_sock)) {
RETVAL_ZVAL(&z_ret, 0, 1);
} else {
add_next_index_zval(z_tab, &z_ret);
}
return SUCCESS;
}
PHP_REDIS_API void
redis_parse_client_list_response(char *response, zval *z_ret)
{
char *p, *s = NULL;
ZVAL_FALSE(z_ret);
if ((p = php_strtok_r(response, _NL, &s)) != NULL) {
array_init(z_ret);
do {
zval z_sub;
redis_parse_client_info(p, &z_sub);
add_next_index_zval(z_ret, &z_sub);
} while ((p = php_strtok_r(NULL, _NL, &s)) != NULL);
}
}
PHP_REDIS_API int
redis_zadd_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx)
{
FailableResultCallback cb;
ZEND_ASSERT(ctx == NULL || ctx == PHPREDIS_CTX_PTR);
cb = ctx ? redis_bulk_double_response : redis_long_response;
return cb(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
}
PHP_REDIS_API int
redis_zrandmember_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx)
{
if (ctx == NULL) {
return redis_string_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR) {
return redis_mbulk_reply_raw(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR + 1) {
return redis_mbulk_reply_zipped_keys_dbl(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else {
ZEND_ASSERT(!"memory corruption?");
return FAILURE;
}
}
PHP_REDIS_API int
redis_zdiff_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx)
{
if (ctx == NULL) {
return redis_mbulk_reply_raw(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR) {
return redis_mbulk_reply_zipped_keys_dbl(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else {
ZEND_ASSERT(!"memory corruption?");
return FAILURE;
}
}
PHP_REDIS_API int
redis_set_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx)
{
if (ctx == NULL) {
return redis_boolean_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR) {
return redis_string_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else {
ZEND_ASSERT(!"memory corruption?");
return FAILURE;
}
}
PHP_REDIS_API int
redis_hrandfield_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx)
{
if (ctx == NULL) {
return redis_string_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR) {
return redis_mbulk_reply_raw(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR + 1) {
return redis_mbulk_reply_zipped_raw(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else {
ZEND_ASSERT(!"memory corruption?");
return FAILURE;
}
}
PHP_REDIS_API int
redis_pop_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx)
{
if (ctx == NULL) {
return redis_string_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR) {
return redis_sock_read_multibulk_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else {
ZEND_ASSERT(!"memory corruption?");
return FAILURE;
}
}
PHP_REDIS_API int
redis_object_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) {
ZEND_ASSERT(ctx == PHPREDIS_CTX_PTR || ctx == PHPREDIS_CTX_PTR + 1);
if (ctx == PHPREDIS_CTX_PTR) {
return redis_long_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else {
return redis_string_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
}
}
PHP_REDIS_API int
redis_read_lpos_response(zval *zdst, RedisSock *redis_sock, char reply_type,
long long elements, void *ctx)
{
char inbuf[4096];
size_t len;
int i;
if (ctx == NULL) {
if (reply_type != TYPE_INT && reply_type != TYPE_BULK)
return FAILURE;
if (elements > -1) {
ZVAL_LONG(zdst, elements);
} else {
REDIS_ZVAL_NULL(redis_sock, zdst);
}
} else if (ctx == PHPREDIS_CTX_PTR) {
if (reply_type != TYPE_MULTIBULK)
return FAILURE;
array_init(zdst);
for (i = 0; i < elements; ++i) {
if (redis_sock_gets(redis_sock, inbuf, sizeof(inbuf), &len) < 0) {
zval_dtor(zdst);
return FAILURE;
}
add_next_index_long(zdst, atol(inbuf + 1));
}
} else {
ZEND_ASSERT(!"memory corruption?");
return FAILURE;
}
return SUCCESS;
}
PHP_REDIS_API int
redis_lpos_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx)
{
char inbuf[1024] = {0};
int res = SUCCESS;
zval zdst = {0};
size_t len;
/* Attempt to read the LPOS response */
if (redis_sock_gets(redis_sock, inbuf, sizeof(inbuf), &len) < 0 ||
redis_read_lpos_response(&zdst, redis_sock, *inbuf, atoll(inbuf+1), ctx) < 0)
{
ZVAL_FALSE(&zdst);
res = FAILURE;
}
if (IS_ATOMIC(redis_sock)) {
RETVAL_ZVAL(&zdst, 0, 0);
} else {
add_next_index_zval(z_tab, &zdst);
}
return res;
}
PHP_REDIS_API int
redis_select_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab,
void *ctx)
{
if (redis_boolean_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL) < 0)
return FAILURE;
redis_sock->dbNumber = (long)(uintptr_t)ctx;
return SUCCESS;
}
PHP_REDIS_API int
redis_boolean_response_impl(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
zval *z_tab, void *ctx,
SuccessCallback success_callback)
{
char *response;
int response_len;
zend_bool ret = 0;
if ((response = redis_sock_read(redis_sock, &response_len)) != NULL) {
ret = (*response == '+');
efree(response);
}
if (ret && success_callback != NULL) {
success_callback(redis_sock);
}
if (IS_ATOMIC(redis_sock)) {
RETVAL_BOOL(ret);
} else {
add_next_index_bool(z_tab, ret);
}
return ret ? SUCCESS : FAILURE;
}
PHP_REDIS_API int redis_boolean_response(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, zval *z_tab,
void *ctx)
{
return redis_boolean_response_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock,
z_tab, ctx, NULL);
}
PHP_REDIS_API int redis_long_response(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, zval * z_tab,
void *ctx)
{
char *response;
int response_len;
if ((response = redis_sock_read(redis_sock, &response_len)) == NULL || *response != TYPE_INT) {
if (IS_ATOMIC(redis_sock)) {
RETVAL_FALSE;
} else {
add_next_index_bool(z_tab, 0);
}
if (response) efree(response);
return FAILURE;
}
int64_t ret = phpredis_atoi64(response + 1);
if (IS_ATOMIC(redis_sock)) {
if (ret > LONG_MAX) { /* overflow */
RETVAL_STRINGL(response + 1, response_len - 1);
} else {
RETVAL_LONG((long)ret);
}
} else {
if (ret > LONG_MAX) { /* overflow */
add_next_index_stringl(z_tab, response + 1, response_len - 1);
} else {
add_next_index_long(z_tab, (long)ret);
}
}
efree(response);
return SUCCESS;
}
/* Helper method to convert [key, value, key, value] into [key => value,
* key => value] when returning data to the caller. Depending on our decode
* flag we'll convert the value data types */
static void array_zip_values_and_scores(RedisSock *redis_sock, zval *z_tab,
int decode)
{
zval z_ret, z_sub;
HashTable *keytable;
array_init(&z_ret);
keytable = Z_ARRVAL_P(z_tab);
for(zend_hash_internal_pointer_reset(keytable);
zend_hash_has_more_elements(keytable) == SUCCESS;
zend_hash_move_forward(keytable)) {
zval *z_key_p, *z_value_p;
if ((z_key_p = zend_hash_get_current_data(keytable)) == NULL) {
continue; /* this should never happen, according to the PHP people. */
}
/* get current value, a key */
zend_string *hkey = zval_get_string(z_key_p);
/* move forward */
zend_hash_move_forward(keytable);
/* fetch again */
if ((z_value_p = zend_hash_get_current_data(keytable)) == NULL) {
zend_string_release(hkey);
continue; /* this should never happen, according to the PHP people. */
}
/* get current value, a hash value now. */
char *hval = Z_STRVAL_P(z_value_p);
/* Decode the score depending on flag */
if (decode == SCORE_DECODE_INT && Z_STRLEN_P(z_value_p) > 0) {
add_assoc_long_ex(&z_ret, ZSTR_VAL(hkey), ZSTR_LEN(hkey), atoi(hval+1));
} else if (decode == SCORE_DECODE_DOUBLE) {
add_assoc_double_ex(&z_ret, ZSTR_VAL(hkey), ZSTR_LEN(hkey), atof(hval));
} else {
ZVAL_ZVAL(&z_sub, z_value_p, 1, 0);
add_assoc_zval_ex(&z_ret, ZSTR_VAL(hkey), ZSTR_LEN(hkey), &z_sub);
}
zend_string_release(hkey);
}
/* replace */
zval_dtor(z_tab);
ZVAL_ZVAL(z_tab, &z_ret, 0, 0);
}
static int
array_zip_values_recursive(zval *z_tab)
{
zend_string *zkey;
zval z_ret, z_sub, *zv;
array_init(&z_ret);
for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(z_tab));
zend_hash_has_more_elements(Z_ARRVAL_P(z_tab)) == SUCCESS;
zend_hash_move_forward(Z_ARRVAL_P(z_tab))
) {
if ((zv = zend_hash_get_current_data(Z_ARRVAL_P(z_tab))) == NULL) {
zval_dtor(&z_ret);
return FAILURE;
}
if (Z_TYPE_P(zv) == IS_STRING) {
zkey = zval_get_string(zv);
zend_hash_move_forward(Z_ARRVAL_P(z_tab));
if ((zv = zend_hash_get_current_data(Z_ARRVAL_P(z_tab))) == NULL) {
zend_string_release(zkey);
zval_dtor(&z_ret);
return FAILURE;
}
if (Z_TYPE_P(zv) == IS_ARRAY && array_zip_values_recursive(zv) != SUCCESS) {
zend_string_release(zkey);
zval_dtor(&z_ret);
return FAILURE;
}
ZVAL_ZVAL(&z_sub, zv, 1, 0);
add_assoc_zval_ex(&z_ret, ZSTR_VAL(zkey), ZSTR_LEN(zkey), &z_sub);
zend_string_release(zkey);
} else {
if (Z_TYPE_P(zv) == IS_ARRAY && array_zip_values_recursive(zv) != SUCCESS) {
zval_dtor(&z_ret);
return FAILURE;
}
ZVAL_ZVAL(&z_sub, zv, 1, 0);
add_next_index_zval(&z_ret, &z_sub);
}
}
zval_dtor(z_tab);
ZVAL_ZVAL(z_tab, &z_ret, 0, 0);
return SUCCESS;
}
static int
redis_mbulk_reply_zipped(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
zval *z_tab, int unserialize, int decode)
{
int numElems;
if (read_mbulk_header(redis_sock, &numElems) < 0) {
if (IS_ATOMIC(redis_sock)) {
RETVAL_FALSE;
} else {
add_next_index_bool(z_tab, 0);
}
return FAILURE;
}
zval z_multi_result;
array_init(&z_multi_result); /* pre-allocate array for multi's results. */
/* Grab our key, value, key, value array */
redis_mbulk_reply_loop(redis_sock, &z_multi_result, numElems, unserialize);
/* Zip keys and values */
array_zip_values_and_scores(redis_sock, &z_multi_result, decode);
if (IS_ATOMIC(redis_sock)) {
RETVAL_ZVAL(&z_multi_result, 0, 1);
} else {
add_next_index_zval(z_tab, &z_multi_result);
}
return 0;
}
static int
geosearch_cast(zval *zv)
{
if (Z_TYPE_P(zv) == IS_ARRAY) {
zend_hash_apply(Z_ARRVAL_P(zv), geosearch_cast);
} else if (Z_TYPE_P(zv) == IS_STRING) {
convert_to_double(zv);
}
return SUCCESS;
}
PHP_REDIS_API int
redis_read_mpop_response(RedisSock *redis_sock, zval *zdst, int elements,
void *ctx)
{
int subele, keylen;
zval zele = {0};
char *key;
ZEND_ASSERT(ctx == NULL || ctx == PHPREDIS_CTX_PTR);
if (elements < 0) {
REDIS_ZVAL_NULL(redis_sock, zdst);
return SUCCESS;
}
/* Invariant: We should have two elements */
ZEND_ASSERT(elements == 2);
array_init(zdst);
/* Key name and number of entries */
if ((key = redis_sock_read(redis_sock, &keylen)) == NULL ||
read_mbulk_header(redis_sock, &elements) < 0 || elements < 0)
{
if (key) efree(key);
goto fail;
}
add_next_index_stringl(zdst, key, keylen);
efree(key);
array_init_size(&zele, elements);
if (ctx == PHPREDIS_CTX_PTR) {
int i;
for (i = 0; i < elements; i++) {
if (read_mbulk_header(redis_sock, &subele) < 0 || subele != 2) {
zval_dtor(&zele);
goto fail;
}
redis_mbulk_reply_loop(redis_sock, &zele, subele, UNSERIALIZE_KEYS);
}
array_zip_values_and_scores(redis_sock, &zele, SCORE_DECODE_DOUBLE);
} else {
redis_mbulk_reply_loop(redis_sock, &zele, elements, UNSERIALIZE_ALL);
}
add_next_index_zval(zdst, &zele);
return SUCCESS;
fail:
zval_dtor(zdst);
ZVAL_FALSE(zdst);
return FAILURE;
}
PHP_REDIS_API int
redis_mpop_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
zval *z_tab, void *ctx)
{
int elements, res = SUCCESS;
zval zret = {0};
if (read_mbulk_header(redis_sock, &elements) == FAILURE ||
redis_read_mpop_response(redis_sock, &zret, elements, ctx) == FAILURE)
{
res = FAILURE;
ZVAL_FALSE(&zret);
}
if (IS_ATOMIC(redis_sock)) {
RETVAL_ZVAL(&zret, 0, 0);
} else {
add_next_index_zval(z_tab, &zret);
}
return res;
}
#if PHP_VERSION_ID < 80200
static HashTable *zend_array_to_list(HashTable *arr) {
zval zret = {0}, *zv;
array_init_size(&zret, zend_hash_num_elements(arr));
ZEND_HASH_FOREACH_VAL(arr, zv) {
Z_TRY_ADDREF_P(zv);
add_next_index_zval(&zret, zv);
} ZEND_HASH_FOREACH_END();
return Z_ARRVAL(zret);
}
#endif
PHP_REDIS_API int
redis_read_geosearch_response(zval *zdst, RedisSock *redis_sock,
long long elements, int with_aux_data)
{
zval z_multi_result, z_sub, *z_ele, *zv;
zend_string *zkey;
/* Handle the trivial "empty" result first */
if (elements < 0 && redis_sock->null_mbulk_as_null) {
ZVAL_NULL(zdst);
return SUCCESS;
}
array_init(zdst);
if (with_aux_data == 0) {
redis_mbulk_reply_loop(redis_sock, zdst, elements, UNSERIALIZE_NONE);
} else {
array_init(&z_multi_result);
redis_read_multibulk_recursive(redis_sock, elements, 0, &z_multi_result);
ZEND_HASH_FOREACH_VAL(Z_ARRVAL(z_multi_result), z_ele) {
// The first item in the sub-array is always the name of the returned item
zv = zend_hash_index_find(Z_ARRVAL_P(z_ele), 0);
zkey = zval_get_string(zv);
zend_hash_index_del(Z_ARRVAL_P(z_ele), 0);
// The other information is returned in the following order as successive
// elements of the sub-array: distance, geohash, coordinates
zend_hash_apply(Z_ARRVAL_P(z_ele), geosearch_cast);
// Reindex elements so they start at zero */
ZVAL_ARR(&z_sub, zend_array_to_list(Z_ARRVAL_P(z_ele)));
add_assoc_zval_ex(zdst, ZSTR_VAL(zkey), ZSTR_LEN(zkey), &z_sub);
zend_string_release(zkey);
} ZEND_HASH_FOREACH_END();
// Cleanup
zval_dtor(&z_multi_result);
}
return SUCCESS;
}
PHP_REDIS_API int
redis_geosearch_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
zval *z_tab, void *ctx)
{
zval zret = {0};
int elements;
if (read_mbulk_header(redis_sock, &elements) < 0 ||
redis_read_geosearch_response(&zret, redis_sock, elements, ctx != NULL) < 0)
{
ZVAL_FALSE(&zret);
}
if (IS_ATOMIC(redis_sock)) {
RETVAL_ZVAL(&zret, 0, 1);
} else {
add_next_index_zval(z_tab, &zret);
}
return SUCCESS;
}
static int
redis_client_trackinginfo_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx)
{
int numElems;
zval z_ret;
if (read_mbulk_header(redis_sock, &numElems) < 0) {
if (IS_ATOMIC(redis_sock)) {
RETVAL_FALSE;
} else {
add_next_index_bool(z_tab, 0);
}
return FAILURE;
}
array_init(&z_ret);
redis_read_multibulk_recursive(redis_sock, numElems, 0, &z_ret);
array_zip_values_and_scores(redis_sock, &z_ret, 0);
if (IS_ATOMIC(redis_sock)) {
RETVAL_ZVAL(&z_ret, 0, 1);
} else {
add_next_index_zval(z_tab, &z_ret);
}
return SUCCESS;
}
PHP_REDIS_API int
redis_client_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx)
{
if (ctx == NULL) {
return redis_client_info_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR) {
return redis_client_list_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR + 1) {
return redis_boolean_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR + 2) {
return redis_long_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR + 3) {
return redis_string_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR + 4) {
return redis_client_trackinginfo_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else {
ZEND_ASSERT(!"memory corruption?");
return FAILURE;
}
}
static int
redis_function_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx)
{
int numElems;
zval z_ret;
if (read_mbulk_header(redis_sock, &numElems) < 0) {
if (IS_ATOMIC(redis_sock)) {
RETVAL_FALSE;
} else {
add_next_index_bool(z_tab, 0);
}
return FAILURE;
}
array_init(&z_ret);
redis_read_multibulk_recursive(redis_sock, numElems, 0, &z_ret);
array_zip_values_recursive(&z_ret);
if (IS_ATOMIC(redis_sock)) {
RETVAL_ZVAL(&z_ret, 0, 1);
} else {
add_next_index_zval(z_tab, &z_ret);
}
return SUCCESS;
}
PHP_REDIS_API int
redis_function_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx)
{
if (ctx == NULL) {
return redis_boolean_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR) {
return redis_string_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR + 1) {
return redis_function_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else {
ZEND_ASSERT(!"memory corruption?");
return FAILURE;
}
}
static int
redis_command_info_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx)
{
int numElems;
zval z_ret;
if (read_mbulk_header(redis_sock, &numElems) < 0) {
if (IS_ATOMIC(redis_sock)) {
RETVAL_FALSE;
} else {
add_next_index_bool(z_tab, 0);
}
return FAILURE;
}
array_init(&z_ret);
redis_read_multibulk_recursive(redis_sock, numElems, 0, &z_ret);
if (IS_ATOMIC(redis_sock)) {
RETVAL_ZVAL(&z_ret, 0, 1);
} else {
add_next_index_zval(z_tab, &z_ret);
}
return SUCCESS;
}
PHP_REDIS_API int
redis_command_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx)
{
if (ctx == NULL) {
return redis_command_info_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR) {
return redis_long_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR + 1) {
return redis_mbulk_reply_raw(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else {
ZEND_ASSERT(!"memory corruption?");
return FAILURE;
}
}
/* Helper function to consume Redis stream message data. This is useful for
* multiple stream callers (e.g. XREAD[GROUP], and X[REV]RANGE handlers). */
PHP_REDIS_API int
redis_read_stream_messages(RedisSock *redis_sock, int count, zval *z_ret
)
{
zval z_message;
int i, mhdr, fields;
char *id = NULL;
int idlen;
/* Iterate over each message */
for (i = 0; i < count; i++) {
/* Consume inner multi-bulk header, message ID itself and finally
* the multi-bulk header for field and values */
if ((read_mbulk_header(redis_sock, &mhdr) < 0 || mhdr != 2) ||
((id = redis_sock_read(redis_sock, &idlen)) == NULL) ||
(read_mbulk_header(redis_sock, &fields) < 0 ||
(fields > 0 && fields % 2 != 0)))
{
if (id) efree(id);
return -1;
}
if (fields < 0) {
add_assoc_null_ex(z_ret, id, idlen);
} else {
array_init(&z_message);
redis_mbulk_reply_loop(redis_sock, &z_message, fields, UNSERIALIZE_VALS);
array_zip_values_and_scores(redis_sock, &z_message, SCORE_DECODE_NONE);
add_assoc_zval_ex(z_ret, id, idlen, &z_message);
}
efree(id);
}
return 0;
}
PHP_REDIS_API int
redis_xrange_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
zval *z_tab, void *ctx)
{
zval z_messages;
int messages;
array_init(&z_messages);
if (read_mbulk_header(redis_sock, &messages) < 0 ||
redis_read_stream_messages(redis_sock, messages, &z_messages) < 0)
{
zval_dtor(&z_messages);
if (IS_ATOMIC(redis_sock)) {
RETVAL_FALSE;
} else {
add_next_index_bool(z_tab, 0);
}
return -1;
}
if (IS_ATOMIC(redis_sock)) {
RETVAL_ZVAL(&z_messages, 0, 1);
} else {
add_next_index_zval(z_tab, &z_messages);
}
return 0;
}
PHP_REDIS_API int
redis_read_stream_messages_multi(RedisSock *redis_sock, int count, zval *z_streams
)
{
zval z_messages;
int i, shdr, messages;
char *id = NULL;
int idlen;
for (i = 0; i < count; i++) {
if ((read_mbulk_header(redis_sock, &shdr) < 0 || shdr != 2) ||
(id = redis_sock_read(redis_sock, &idlen)) == NULL ||
read_mbulk_header(redis_sock, &messages) < 0)
{
if (id) efree(id);
return -1;
}
array_init(&z_messages);
if (redis_read_stream_messages(redis_sock, messages, &z_messages) < 0)
goto failure;
add_assoc_zval_ex(z_streams, id, idlen, &z_messages);
efree(id);
}
return 0;
failure:
efree(id);
zval_dtor(&z_messages);
return -1;
}
PHP_REDIS_API int
redis_xread_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
zval *z_tab, void *ctx)
{
zval z_rv;
int streams;
if (read_mbulk_header(redis_sock, &streams) < 0)
goto failure;
if (streams == -1 && redis_sock->null_mbulk_as_null) {
ZVAL_NULL(&z_rv);
} else {
array_init(&z_rv);
if (redis_read_stream_messages_multi(redis_sock, streams, &z_rv) < 0)
goto cleanup;
}
if (IS_ATOMIC(redis_sock)) {
RETVAL_ZVAL(&z_rv, 0, 1);
} else {
add_next_index_zval(z_tab, &z_rv);
}
return 0;
cleanup:
zval_dtor(&z_rv);
failure:
if (IS_ATOMIC(redis_sock)) {
RETVAL_FALSE;
} else {
add_next_index_bool(z_tab, 0);
}
return -1;
}
/* A helper method to read X[AUTO]CLAIM messages into an array. */
static int
redis_read_xclaim_ids(RedisSock *redis_sock, int count, zval *rv) {
zval z_msg;
REDIS_REPLY_TYPE type;
char *id = NULL;
int i, fields, idlen;
long li;
for (i = 0; i < count; i++) {
id = NULL;
/* Consume inner reply type */
if (redis_read_reply_type(redis_sock, &type, &li) < 0 ||
(type != TYPE_BULK && type != TYPE_MULTIBULK) ||
(type == TYPE_BULK && li <= 0)) return -1;
/* TYPE_BULK is the JUSTID variant, otherwise it's standard xclaim response */
if (type == TYPE_BULK) {
if ((id = redis_sock_read_bulk_reply(redis_sock, (size_t)li)) == NULL)
return -1;
add_next_index_stringl(rv, id, li);
efree(id);
} else {
if ((li != 2 || (id = redis_sock_read(redis_sock, &idlen)) == NULL) ||
(read_mbulk_header(redis_sock, &fields) < 0 || fields % 2 != 0))
{
if (id) efree(id);
return -1;
}
array_init(&z_msg);
redis_mbulk_reply_loop(redis_sock, &z_msg, fields, UNSERIALIZE_VALS);
array_zip_values_and_scores(redis_sock, &z_msg, SCORE_DECODE_NONE);
add_assoc_zval_ex(rv, id, idlen, &z_msg);
efree(id);
}
}
return 0;
}
/* Read an X[AUTO]CLAIM reply having already consumed the reply-type byte. */
PHP_REDIS_API int
redis_read_xclaim_reply(RedisSock *redis_sock, int count, int is_xautoclaim, zval *rv) {
REDIS_REPLY_TYPE type;
zval z_msgs = {0};
char *id = NULL;
long id_len = 0;
int messages;
ZEND_ASSERT(!is_xautoclaim || count == 3);
ZVAL_UNDEF(rv);
/* If this is XAUTOCLAIM consume the BULK ID and then the actual number of IDs.
* Otherwise, our 'count' argument is the number of IDs. */
if (is_xautoclaim) {
if (redis_read_reply_type(redis_sock, &type, &id_len) < 0 || type != TYPE_BULK)
goto failure;
if ((id = redis_sock_read_bulk_reply(redis_sock, id_len)) == NULL)
goto failure;
if (read_mbulk_header(redis_sock, &messages) < 0)
goto failure;
} else {
messages = count;
}
array_init(&z_msgs);
if (redis_read_xclaim_ids(redis_sock, messages, &z_msgs) < 0)
goto failure;
/* If XAUTOCLAIM we now need to consume the final array of message IDs */
if (is_xautoclaim) {
zval z_deleted = {0};
if (redis_sock_read_multibulk_reply_zval(redis_sock, &z_deleted) == NULL)
goto failure;
array_init(rv);
// Package up ID, message, and deleted messages in our reply
add_next_index_stringl(rv, id, id_len);
add_next_index_zval(rv, &z_msgs);
add_next_index_zval(rv, &z_deleted);
efree(id);
} else {
// We just want the messages
ZVAL_COPY_VALUE(rv, &z_msgs);
}
return 0;
failure:
zval_dtor(&z_msgs);
zval_dtor(rv);
if (id) efree(id);
return -1;
}
PHP_REDIS_API int
redis_xclaim_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
zval *z_tab, void *ctx)
{
zval z_ret = {0};
int count;
ZEND_ASSERT(ctx == NULL || ctx == PHPREDIS_CTX_PTR);
if (read_mbulk_header(redis_sock, &count) < 0)
goto failure;
if (redis_read_xclaim_reply(redis_sock, count, ctx == PHPREDIS_CTX_PTR, &z_ret) < 0)
goto failure;
if (IS_ATOMIC(redis_sock)) {
RETVAL_ZVAL(&z_ret, 0, 1);
} else {
add_next_index_zval(z_tab, &z_ret);
}
return 0;
failure:
if (IS_ATOMIC(redis_sock)) {
RETVAL_FALSE;
} else {
add_next_index_bool(z_tab, 0);
}
return -1;
}
PHP_REDIS_API int
redis_read_xinfo_response(RedisSock *redis_sock, zval *z_ret, int elements)
{
zval zv;
int i, len = 0;
char *key = NULL, *data;
REDIS_REPLY_TYPE type;
long li;
for (i = 0; i < elements; ++i) {
if (redis_read_reply_type(redis_sock, &type, &li) < 0) {
goto failure;
}
switch (type) {
case TYPE_BULK:
if ((data = redis_sock_read_bulk_reply(redis_sock, li)) == NULL) {
if (!key) goto failure;
add_assoc_null_ex(z_ret, key, len);
efree(key);
key = NULL;
} else if (key) {
add_assoc_stringl_ex(z_ret, key, len, data, li);
efree(data);
efree(key);
key = NULL;
} else {
key = data;
len = li;
}
break;
case TYPE_INT:
if (key) {
add_assoc_long_ex(z_ret, key, len, li);
efree(key);
key = NULL;
} else {
len = spprintf(&key, 0, "%ld", li);
}
break;
case TYPE_MULTIBULK:
array_init(&zv);
if (redis_read_xinfo_response(redis_sock, &zv, li) != SUCCESS) {
zval_dtor(&zv);
goto failure;
}
if (key) {
add_assoc_zval_ex(z_ret, key, len, &zv);
efree(key);
key = NULL;
} else {
add_next_index_zval(z_ret, &zv);
}
break;
default:
goto failure;
}
}
return SUCCESS;
failure:
if (key) efree(key);
return FAILURE;
}
PHP_REDIS_API int
redis_xinfo_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx)
{
zval z_ret;
int elements;
if (read_mbulk_header(redis_sock, &elements) == SUCCESS) {
array_init(&z_ret);
if (redis_read_xinfo_response(redis_sock, &z_ret, elements) == SUCCESS) {
if (IS_ATOMIC(redis_sock)) {
RETVAL_ZVAL(&z_ret, 0, 1);
} else {
add_next_index_zval(z_tab, &z_ret);
}
return SUCCESS;
}
zval_dtor(&z_ret);
}
if (IS_ATOMIC(redis_sock)) {
RETVAL_FALSE;
} else {
add_next_index_bool(z_tab, 0);
}
return FAILURE;
}
PHP_REDIS_API int
redis_acl_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx)
{
if (ctx == NULL) {
return redis_read_variant_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR) {
return redis_boolean_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR + 1) {
return redis_string_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR + 2) {
return redis_long_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR + 3) {
return redis_acl_getuser_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR + 4) {
return redis_acl_log_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else {
ZEND_ASSERT(!"memory corruption?");
return FAILURE;
}
}
PHP_REDIS_API int
redis_read_acl_log_reply(RedisSock *redis_sock, zval *zret, long count) {
zval zsub;
int i, nsub;
for (i = 0; i < count; i++) {
if (read_mbulk_header(redis_sock, &nsub) < 0 || nsub % 2 != 0)
return FAILURE;
array_init(&zsub);
if (redis_mbulk_reply_zipped_raw_variant(redis_sock, &zsub, nsub) == FAILURE)
return FAILURE;
add_next_index_zval(zret, &zsub);
}
return SUCCESS;
}
PHP_REDIS_API int
redis_read_acl_getuser_reply(RedisSock *redis_sock, zval *zret, long count) {
REDIS_REPLY_TYPE type;
zval zv;
char *key, *val;
long vlen;
int klen, i;
for (i = 0; i < count; i += 2) {
if (!(key = redis_sock_read(redis_sock, &klen)) ||
redis_read_reply_type(redis_sock, &type, &vlen) < 0 ||
(type != TYPE_BULK && type != TYPE_MULTIBULK) ||
vlen > INT_MAX)
{
if (key) efree(key);
return FAILURE;
}
if (type == TYPE_BULK) {
if (!(val = redis_sock_read_bulk_reply(redis_sock, (int)vlen)))
return FAILURE;
add_assoc_stringl_ex(zret, key, klen, val, vlen);
efree(val);
} else {
array_init(&zv);
redis_mbulk_reply_loop(redis_sock, &zv, (int)vlen, UNSERIALIZE_NONE);
add_assoc_zval_ex(zret, key, klen, &zv);
}
efree(key);
}
return SUCCESS;
}
int redis_acl_custom_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx,
int (*cb)(RedisSock*, zval*, long)) {
REDIS_REPLY_TYPE type;
int res = FAILURE;
zval zret;
long len;
if (redis_read_reply_type(redis_sock, &type, &len) == 0 && type == TYPE_MULTIBULK) {
array_init(&zret);
res = cb(redis_sock, &zret, len);
if (res == FAILURE) {
zval_dtor(&zret);
ZVAL_FALSE(&zret);
}
} else {
ZVAL_FALSE(&zret);
}
if (IS_ATOMIC(redis_sock)) {
RETVAL_ZVAL(&zret, 0, 0);
} else {
add_next_index_zval(z_tab, &zret);
}
return res;
}
int redis_acl_getuser_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) {
return redis_acl_custom_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, ctx,
redis_read_acl_getuser_reply);
}
int redis_acl_log_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) {
return redis_acl_custom_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, ctx,
redis_read_acl_log_reply);
}
/* Zipped key => value reply but we don't touch anything (e.g. CONFIG GET) */
PHP_REDIS_API int redis_mbulk_reply_zipped_raw(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx)
{
return redis_mbulk_reply_zipped(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock,
z_tab, UNSERIALIZE_NONE, SCORE_DECODE_NONE);
}
/* Zipped key => value reply unserializing keys and decoding the score as an integer (PUBSUB) */
PHP_REDIS_API int redis_mbulk_reply_zipped_keys_int(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
zval *z_tab, void *ctx)
{
return redis_mbulk_reply_zipped(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock,
z_tab, UNSERIALIZE_KEYS, SCORE_DECODE_INT);
}
/* Zipped key => value reply unserializing keys and decoding the score as a double (ZSET commands) */
PHP_REDIS_API int redis_mbulk_reply_zipped_keys_dbl(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
zval *z_tab, void *ctx)
{
return redis_mbulk_reply_zipped(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock,
z_tab, UNSERIALIZE_KEYS, SCORE_DECODE_DOUBLE);
}
/* Zipped key => value reply where only the values are unserialized (e.g. HMGET) */
PHP_REDIS_API int redis_mbulk_reply_zipped_vals(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
zval *z_tab, void *ctx)
{
return redis_mbulk_reply_zipped(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock,
z_tab, UNSERIALIZE_VALS, SCORE_DECODE_NONE);
}
PHP_REDIS_API int
redis_1_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx)
{
char *response;
int response_len;
zend_bool ret = 0;
if ((response = redis_sock_read(redis_sock, &response_len)) != NULL) {
ret = (response[1] == '1');
efree(response);
}
if (IS_ATOMIC(redis_sock)) {
RETVAL_BOOL(ret);
} else {
add_next_index_bool(z_tab, ret);
}
return ret ? SUCCESS : FAILURE;
}
PHP_REDIS_API int redis_string_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) {
char *response;
int response_len;
if ((response = redis_sock_read(redis_sock, &response_len))
== NULL)
{
if (IS_ATOMIC(redis_sock)) {
RETVAL_FALSE;
} else {
add_next_index_bool(z_tab, 0);
}
return FAILURE;
}
if (IS_ATOMIC(redis_sock)) {
if (!redis_unpack(redis_sock, response, response_len, return_value)) {
RETVAL_STRINGL(response, response_len);
}
} else {
zval z_unpacked;
if (redis_unpack(redis_sock, response, response_len, &z_unpacked)) {
add_next_index_zval(z_tab, &z_unpacked);
} else {
add_next_index_stringl(z_tab, response, response_len);
}
}
efree(response);
return SUCCESS;
}
/* like string response, but never unserialized. */
PHP_REDIS_API int
redis_ping_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
zval *z_tab, void *ctx)
{
char *response;
int response_len;
if ((response = redis_sock_read(redis_sock, &response_len))
== NULL)
{
if (IS_ATOMIC(redis_sock)) {
RETVAL_FALSE;
} else {
add_next_index_bool(z_tab, 0);
}
return FAILURE;
}
if (IS_ATOMIC(redis_sock)) {
RETVAL_STRINGL(response, response_len);
} else {
add_next_index_stringl(z_tab, response, response_len);
}
efree(response);
return SUCCESS;
}
/* Response for DEBUG object which is a formatted single line reply */
PHP_REDIS_API void redis_debug_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
zval *z_tab, void *ctx)
{
char *resp, *p, *p2, *p3, *p4;
int is_numeric, resp_len;
/* Add or return false if we can't read from the socket */
if((resp = redis_sock_read(redis_sock, &resp_len))==NULL) {
if (IS_ATOMIC(redis_sock)) {
RETURN_FALSE;
}
add_next_index_bool(z_tab, 0);
return;
}
zval z_result;
array_init(&z_result);
/* Skip the '+' */
p = resp + 1;
/* : ... */
while((p2 = strchr(p, ':'))!=NULL) {
/* Null terminate at the ':' */
*p2++ = '\0';
/* Null terminate at the space if we have one */
if((p3 = strchr(p2, ' '))!=NULL) {
*p3++ = '\0';
} else {
p3 = resp + resp_len;
}
is_numeric = 1;
for(p4=p2; *p4; ++p4) {
if(*p4 < '0' || *p4 > '9') {
is_numeric = 0;
break;
}
}
/* Add our value */
if(is_numeric) {
add_assoc_long(&z_result, p, atol(p2));
} else {
add_assoc_string(&z_result, p, p2);
}
p = p3;
}
efree(resp);
if (IS_ATOMIC(redis_sock)) {
RETVAL_ZVAL(&z_result, 0, 1);
} else {
add_next_index_zval(z_tab, &z_result);
}
}
PHP_REDIS_API int
redis_sock_configure(RedisSock *redis_sock, HashTable *opts)
{
zend_string *zkey;
zval *val;
ZEND_HASH_FOREACH_STR_KEY_VAL(opts, zkey, val) {
if (zkey == NULL) {
continue;
}
ZVAL_DEREF(val);
if (zend_string_equals_literal_ci(zkey, "host")) {
if (Z_TYPE_P(val) != IS_STRING) {
REDIS_VALUE_EXCEPTION("Invalid host");
return FAILURE;
}
if (redis_sock->host) zend_string_release(redis_sock->host);
redis_sock->host = zval_get_string(val);
} else if (zend_string_equals_literal_ci(zkey, "port")) {
if (Z_TYPE_P(val) != IS_LONG) {
REDIS_VALUE_EXCEPTION("Invalid port");
return FAILURE;
}
redis_sock->port = zval_get_long(val);
} else if (zend_string_equals_literal_ci(zkey, "connectTimeout")) {
if (Z_TYPE_P(val) != IS_LONG && Z_TYPE_P(val) != IS_DOUBLE) {
REDIS_VALUE_EXCEPTION("Invalid connect timeout");
return FAILURE;
}
redis_sock->timeout = zval_get_double(val);
} else if (zend_string_equals_literal_ci(zkey, "readTimeout")) {
if (Z_TYPE_P(val) != IS_LONG && Z_TYPE_P(val) != IS_DOUBLE) {
REDIS_VALUE_EXCEPTION("Invalid read timeout");
return FAILURE;
}
redis_sock->read_timeout = zval_get_double(val);
} else if (zend_string_equals_literal_ci(zkey, "persistent")) {
if (Z_TYPE_P(val) == IS_STRING) {
if (redis_sock->persistent_id) zend_string_release(redis_sock->persistent_id);
redis_sock->persistent_id = zval_get_string(val);
redis_sock->persistent = 1;
} else {
redis_sock->persistent = zval_is_true(val);
}
} else if (zend_string_equals_literal_ci(zkey, "retryInterval")) {
if (Z_TYPE_P(val) != IS_LONG && Z_TYPE_P(val) != IS_DOUBLE) {
REDIS_VALUE_EXCEPTION("Invalid retry interval");
return FAILURE;
}
redis_sock->retry_interval = zval_get_long(val);
} else if (zend_string_equals_literal_ci(zkey, "ssl")) {
if (redis_sock_set_stream_context(redis_sock, val) != SUCCESS) {
REDIS_VALUE_EXCEPTION("Invalid SSL context options");
return FAILURE;
}
} else if (zend_string_equals_literal_ci(zkey, "auth")) {
if (Z_TYPE_P(val) != IS_STRING && Z_TYPE_P(val) != IS_ARRAY) {
REDIS_VALUE_EXCEPTION("Invalid auth credentials");
return FAILURE;
}
redis_sock_set_auth_zval(redis_sock, val);
} else if (zend_string_equals_literal_ci(zkey, "backoff")) {
if (redis_sock_set_backoff(redis_sock, val) != SUCCESS) {
REDIS_VALUE_EXCEPTION("Invalid backoff options");
return FAILURE;
}
} else {
php_error_docref(NULL, E_WARNING, "Skip unknown option '%s'", ZSTR_VAL(zkey));
}
} ZEND_HASH_FOREACH_END();
return SUCCESS;
}
/**
* redis_sock_create
*/
PHP_REDIS_API RedisSock*
redis_sock_create(char *host, int host_len, int port,
double timeout, double read_timeout,
int persistent, char *persistent_id,
long retry_interval)
{
RedisSock *redis_sock;
redis_sock = ecalloc(1, sizeof(RedisSock));
redis_sock->host = zend_string_init(host, host_len, 0);
redis_sock->status = REDIS_SOCK_STATUS_DISCONNECTED;
redis_sock->retry_interval = retry_interval * 1000;
redis_sock->max_retries = 10;
redis_initialize_backoff(&redis_sock->backoff, retry_interval);
redis_sock->persistent = persistent;
if (persistent && persistent_id != NULL) {
redis_sock->persistent_id = zend_string_init(persistent_id, strlen(persistent_id), 0);
}
redis_sock->port = port;
redis_sock->timeout = timeout;
redis_sock->read_timeout = read_timeout;
redis_sock->serializer = REDIS_SERIALIZER_NONE;
redis_sock->compression = REDIS_COMPRESSION_NONE;
redis_sock->mode = ATOMIC;
return redis_sock;
}
static int redis_uniqid(char *buf, size_t buflen) {
struct timeval tv;
gettimeofday(&tv, NULL);
return snprintf(buf, buflen, "phpredis:%08lx%05lx:%08lx",
(long)tv.tv_sec, (long)tv.tv_usec, (long)php_rand());
}
static int redis_stream_liveness_check(php_stream *stream) {
return php_stream_set_option(stream, PHP_STREAM_OPTION_CHECK_LIVENESS,
0, NULL) == PHP_STREAM_OPTION_RETURN_OK ?
SUCCESS : FAILURE;
}
/* Try to get the underlying socket FD for use with poll/select.
* Returns -1 on failure. */
static php_socket_t redis_stream_fd_for_select(php_stream *stream) {
php_socket_t fd;
int flags;
flags = PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL;
if (php_stream_cast(stream, flags, (void*)&fd, 1) == FAILURE)
return -1;
return fd;
}
static int redis_detect_dirty_config(void) {
int val = INI_INT("redis.pconnect.pool_detect_dirty");
if (val >= 0 && val <= 2)
return val;
else if (val > 2)
return 2;
else
return 0;
}
static int redis_pool_poll_timeout(void) {
int val = INI_INT("redis.pconnect.pool_poll_timeout");
if (val >= 0)
return val;
return 0;
}
#define REDIS_POLL_FD_SET(_pfd, _fd, _events) \
(_pfd).fd = _fd; (_pfd).events = _events; (_pfd).revents = 0
/* Try to determine if the socket is out of sync (has unconsumed replies) */
static int redis_stream_detect_dirty(php_stream *stream) {
php_socket_t fd;
php_pollfd pfd;
int rv, action;
/* Short circuit if this is disabled */
if ((action = redis_detect_dirty_config()) == 0)
return SUCCESS;
/* Seek past unconsumed bytes if we detect them */
if (stream->readpos < stream->writepos) {
redisDbgFmt("%s on unconsumed buffer (%ld < %ld)",
action > 1 ? "Aborting" : "Seeking",
(long)stream->readpos, (long)stream->writepos);
/* Abort if we are configured to immediately fail */
if (action == 1)
return FAILURE;
/* Seek to the end of buffered data */
zend_off_t offset = stream->writepos - stream->readpos;
if (php_stream_seek(stream, offset, SEEK_CUR) == FAILURE)
return FAILURE;
}
/* Get the underlying FD */
if ((fd = redis_stream_fd_for_select(stream)) == -1)
return FAILURE;
/* We want to detect a readable socket (it shouln't be) */
REDIS_POLL_FD_SET(pfd, fd, PHP_POLLREADABLE);
rv = php_poll2(&pfd, 1, redis_pool_poll_timeout());
/* If we detect the socket is readable, it's dirty which is
* a failure. Otherwise as best we can tell it's good.
* TODO: We could attempt to consume up to N bytes */
redisDbgFmt("Detected %s socket", rv > 0 ? "readable" : "unreadable");
return rv == 0 ? SUCCESS : FAILURE;
}
static int
redis_sock_check_liveness(RedisSock *redis_sock)
{
char id[64], inbuf[4096];
int idlen, auth;
smart_string cmd = {0};
size_t len;
/* Short circuit if PHP detects the stream isn't live */
if (redis_stream_liveness_check(redis_sock->stream) != SUCCESS)
goto failure;
/* Short circuit if we detect the stream is "dirty", can't or are
configured not to try and fix it */
if (redis_stream_detect_dirty(redis_sock->stream) != SUCCESS)
goto failure;
redis_sock->status = REDIS_SOCK_STATUS_CONNECTED;
if (!INI_INT("redis.pconnect.echo_check_liveness")) {
return SUCCESS;
}
/* AUTH (if we need it) */
auth = redis_sock_append_auth(redis_sock, &cmd);
/* ECHO challenge/response */
idlen = redis_uniqid(id, sizeof(id));
REDIS_CMD_INIT_SSTR_STATIC(&cmd, 1, "ECHO");
redis_cmd_append_sstr(&cmd, id, idlen);
/* Send command(s) and make sure we can consume reply(ies) */
if (redis_sock_write(redis_sock, cmd.c, cmd.len) < 0) {
smart_string_free(&cmd);
goto failure;
}
smart_string_free(&cmd);
if (redis_sock_gets(redis_sock, inbuf, sizeof(inbuf) - 1, &len) < 0) {
goto failure;
}
if (auth) {
if (strncmp(inbuf, "+OK", 3) == 0 || strncmp(inbuf, "-ERR Client sent AUTH", 21) == 0) {
/* successfully authenticated or authentication isn't required */
if (redis_sock_gets(redis_sock, inbuf, sizeof(inbuf) - 1, &len) < 0) {
goto failure;
}
} else if (strncmp(inbuf, "-NOAUTH", 7) == 0) {
/* connection is fine but authentication failed, next command must fails too */
if (redis_sock_gets(redis_sock, inbuf, sizeof(inbuf) - 1, &len) < 0 || strncmp(inbuf, "-NOAUTH", 7) != 0) {
goto failure;
}
return SUCCESS;
} else {
goto failure;
}
redis_sock->status = REDIS_SOCK_STATUS_AUTHENTICATED;
} else {
if (strncmp(inbuf, "-NOAUTH", 7) == 0) {
/* connection is fine but authentication required */
return SUCCESS;
}
}
/* check echo response */
if ((redis_sock->sentinel && (
strncmp(inbuf, "-ERR unknown command", 20) != 0 ||
strstr(inbuf, id) == NULL
)) || *inbuf != TYPE_BULK || atoi(inbuf + 1) != idlen ||
redis_sock_gets(redis_sock, inbuf, sizeof(inbuf) - 1, &len) < 0 ||
strncmp(inbuf, id, idlen) != 0
) {
goto failure;
}
return SUCCESS;
failure:
redis_sock->status = REDIS_SOCK_STATUS_DISCONNECTED;
if (redis_sock->stream) {
php_stream_pclose(redis_sock->stream);
redis_sock->stream = NULL;
}
return FAILURE;
}
/**
* redis_sock_connect
*/
PHP_REDIS_API int redis_sock_connect(RedisSock *redis_sock)
{
struct timeval tv, read_tv, *tv_ptr = NULL;
zend_string *persistent_id = NULL, *estr = NULL;
char host[1024], scheme[8], *pos, *address;
const char *fmtstr = "%s://%s:%d";
int host_len, usocket = 0, err = 0, tcp_flag = 1;
ConnectionPool *p = NULL;
if (redis_sock->stream != NULL) {
redis_sock_disconnect(redis_sock, 0, 1);
}
address = ZSTR_VAL(redis_sock->host);
if ((pos = strstr(address, "://")) == NULL) {
strcpy(scheme, redis_sock->stream_ctx ? "ssl" : "tcp");
} else {
snprintf(scheme, sizeof(scheme), "%.*s", (int)(pos - address), address);
address = pos + sizeof("://") - 1;
}
if (address[0] == '/' && redis_sock->port < 1) {
host_len = snprintf(host, sizeof(host), "unix://%s", address);
usocket = 1;
} else {
if(redis_sock->port == 0)
redis_sock->port = 6379;
#ifdef HAVE_IPV6
/* If we've got IPv6 and find a colon in our address, convert to proper
* IPv6 [host]:port format */
if (strchr(address, ':') != NULL && strchr(address, '[') == NULL) {
fmtstr = "%s://[%s]:%d";
}
#endif
host_len = snprintf(host, sizeof(host), fmtstr, scheme, address, redis_sock->port);
}
if (redis_sock->persistent) {
if (INI_INT("redis.pconnect.pooling_enabled")) {
p = redis_sock_get_connection_pool(redis_sock);
if (zend_llist_count(&p->list) > 0) {
redis_sock->stream = *(php_stream **)zend_llist_get_last(&p->list);
zend_llist_remove_tail(&p->list);
if (redis_sock_check_liveness(redis_sock) == SUCCESS) {
return SUCCESS;
}
p->nb_active--;
}
int limit = INI_INT("redis.pconnect.connection_limit");
if (limit > 0 && p->nb_active >= limit) {
redis_sock_set_err(redis_sock, "Connection limit reached", sizeof("Connection limit reached") - 1);
return FAILURE;
}
gettimeofday(&tv, NULL);
persistent_id = strpprintf(0, "phpredis_%ld%ld", tv.tv_sec, tv.tv_usec);
} else {
if (redis_sock->persistent_id) {
persistent_id = strpprintf(0, "phpredis:%s:%s", host, ZSTR_VAL(redis_sock->persistent_id));
} else {
persistent_id = strpprintf(0, "phpredis:%s:%f", host, redis_sock->timeout);
}
}
}
tv.tv_sec = (time_t)redis_sock->timeout;
tv.tv_usec = (int)((redis_sock->timeout - tv.tv_sec) * 1000000);
if (tv.tv_sec != 0 || tv.tv_usec != 0) {
tv_ptr = &tv;
}
redis_sock->stream = php_stream_xport_create(host, host_len,
0, STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT,
persistent_id ? ZSTR_VAL(persistent_id) : NULL,
tv_ptr, redis_sock->stream_ctx, &estr, &err);
if (persistent_id) {
zend_string_release(persistent_id);
}
if (!redis_sock->stream) {
if (estr) {
redis_sock_set_err(redis_sock, ZSTR_VAL(estr), ZSTR_LEN(estr));
zend_string_release(estr);
}
return FAILURE;
}
if (p) p->nb_active++;
/* Attempt to set TCP_NODELAY/TCP_KEEPALIVE if we're not using a unix socket. */
if (!usocket) {
php_netstream_data_t *sock = (php_netstream_data_t*)redis_sock->stream->abstract;
err = setsockopt(sock->socket, IPPROTO_TCP, TCP_NODELAY, (char*) &tcp_flag, sizeof(tcp_flag));
PHPREDIS_NOTUSED(err);
err = setsockopt(sock->socket, SOL_SOCKET, SO_KEEPALIVE, (char*) &redis_sock->tcp_keepalive, sizeof(redis_sock->tcp_keepalive));
PHPREDIS_NOTUSED(err);
}
php_stream_auto_cleanup(redis_sock->stream);
read_tv.tv_sec = (time_t)redis_sock->read_timeout;
read_tv.tv_usec = (int)((redis_sock->read_timeout - read_tv.tv_sec) * 1000000);
if (read_tv.tv_sec != 0 || read_tv.tv_usec != 0) {
php_stream_set_option(redis_sock->stream,PHP_STREAM_OPTION_READ_TIMEOUT,
0, &read_tv);
}
php_stream_set_option(redis_sock->stream,
PHP_STREAM_OPTION_WRITE_BUFFER, PHP_STREAM_BUFFER_NONE, NULL);
redis_sock->status = REDIS_SOCK_STATUS_CONNECTED;
return SUCCESS;
}
/**
* redis_sock_server_open
*/
PHP_REDIS_API int
redis_sock_server_open(RedisSock *redis_sock)
{
if (redis_sock) {
switch (redis_sock->status) {
case REDIS_SOCK_STATUS_DISCONNECTED:
if (redis_sock_connect(redis_sock) != SUCCESS) {
break;
}
redis_sock->status = REDIS_SOCK_STATUS_CONNECTED;
// fall through
case REDIS_SOCK_STATUS_CONNECTED:
if (redis_sock_auth(redis_sock) != SUCCESS) {
break;
}
redis_sock->status = REDIS_SOCK_STATUS_AUTHENTICATED;
// fall through
case REDIS_SOCK_STATUS_AUTHENTICATED:
if (redis_sock->dbNumber && reselect_db(redis_sock) != SUCCESS) {
break;
}
redis_sock->status = REDIS_SOCK_STATUS_READY;
// fall through
case REDIS_SOCK_STATUS_READY:
return SUCCESS;
default:
return FAILURE;
}
}
return FAILURE;
}
/**
* redis_sock_disconnect
*/
PHP_REDIS_API int
redis_sock_disconnect(RedisSock *redis_sock, int force, int is_reset_mode)
{
if (redis_sock == NULL) {
return FAILURE;
} else if (redis_sock->stream) {
if (redis_sock->persistent) {
ConnectionPool *p = NULL;
if (INI_INT("redis.pconnect.pooling_enabled")) {
p = redis_sock_get_connection_pool(redis_sock);
}
if (force || !IS_ATOMIC(redis_sock)) {
php_stream_pclose(redis_sock->stream);
free_reply_callbacks(redis_sock);
if (p) p->nb_active--;
} else if (p) {
zend_llist_prepend_element(&p->list, &redis_sock->stream);
}
} else {
php_stream_close(redis_sock->stream);
}
redis_sock->stream = NULL;
}
if (is_reset_mode) {
redis_sock->mode = ATOMIC;
}
redis_sock->status = REDIS_SOCK_STATUS_DISCONNECTED;
redis_sock->watching = 0;
return SUCCESS;
}
/**
* redis_sock_set_err
*/
PHP_REDIS_API void
redis_sock_set_err(RedisSock *redis_sock, const char *msg, int msg_len)
{
// Free our last error
if (redis_sock->err != NULL) {
zend_string_release(redis_sock->err);
redis_sock->err = NULL;
}
if (msg != NULL && msg_len > 0) {
// Copy in our new error message
redis_sock->err = zend_string_init(msg, msg_len, 0);
}
}
PHP_REDIS_API int
redis_sock_set_stream_context(RedisSock *redis_sock, zval *options)
{
zend_string *zkey;
zval *z_ele;
if (!redis_sock || Z_TYPE_P(options) != IS_ARRAY)
return FAILURE;
if (!redis_sock->stream_ctx)
redis_sock->stream_ctx = php_stream_context_alloc();
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(options), zkey, z_ele) {
if (zkey != NULL) {
php_stream_context_set_option(redis_sock->stream_ctx, "ssl", ZSTR_VAL(zkey), z_ele);
}
} ZEND_HASH_FOREACH_END();
return SUCCESS;
}
PHP_REDIS_API int
redis_sock_set_backoff(RedisSock *redis_sock, zval *options)
{
zend_string *zkey;
zend_long val;
zval *z_ele;
if (!redis_sock || Z_TYPE_P(options) != IS_ARRAY) {
return FAILURE;
}
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(options), zkey, z_ele) {
if (zkey != NULL) {
ZVAL_DEREF(z_ele);
if (zend_string_equals_literal_ci(zkey, "algorithm")) {
if ((val = zval_get_long(z_ele)) < 0 || val >= REDIS_BACKOFF_ALGORITHMS) {
return FAILURE;
}
redis_sock->backoff.algorithm = val;
} else if (zend_string_equals_literal_ci(zkey, "base")) {
if ((val = zval_get_long(z_ele)) < 0) {
return FAILURE;
}
redis_sock->backoff.base = val * 1000;
} else if (zend_string_equals_literal_ci(zkey, "cap")) {
if ((val = zval_get_long(z_ele)) < 0) {
return FAILURE;
}
redis_sock->backoff.cap = val * 1000;
} else {
php_error_docref(NULL, E_WARNING, "Skip unknown backoff option '%s'", ZSTR_VAL(zkey));
}
}
} ZEND_HASH_FOREACH_END();
return SUCCESS;
}
/**
* redis_sock_read_multibulk_reply
*/
PHP_REDIS_API int redis_sock_read_multibulk_reply(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, zval *z_tab,
void *ctx)
{
zval z_multi_result;
int numElems;
if (read_mbulk_header(redis_sock, &numElems) < 0) {
if (IS_ATOMIC(redis_sock)) {
RETVAL_FALSE;
} else {
add_next_index_bool(z_tab, 0);
}
return FAILURE;
}
if (numElems == -1 && redis_sock->null_mbulk_as_null) {
ZVAL_NULL(&z_multi_result);
} else {
array_init(&z_multi_result);
redis_mbulk_reply_loop(redis_sock, &z_multi_result, numElems, UNSERIALIZE_ALL);
}
if (IS_ATOMIC(redis_sock)) {
RETVAL_ZVAL(&z_multi_result, 0, 1);
} else {
add_next_index_zval(z_tab, &z_multi_result);
}
return 0;
}
/* Like multibulk reply, but don't touch the values, they won't be unserialized
* (this is used by HKEYS). */
PHP_REDIS_API int
redis_mbulk_reply_raw(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx)
{
int numElems;
if (read_mbulk_header(redis_sock, &numElems) < 0) {
if (IS_ATOMIC(redis_sock)) {
RETVAL_FALSE;
} else {
add_next_index_bool(z_tab, 0);
}
return FAILURE;
}
zval z_multi_result;
array_init(&z_multi_result); /* pre-allocate array for multi's results. */
redis_mbulk_reply_loop(redis_sock, &z_multi_result, numElems, UNSERIALIZE_NONE);
if (IS_ATOMIC(redis_sock)) {
RETVAL_ZVAL(&z_multi_result, 0, 1);
} else {
add_next_index_zval(z_tab, &z_multi_result);
}
return SUCCESS;
}
PHP_REDIS_API int
redis_mbulk_reply_double(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx)
{
char *line;
int i, numElems, len;
zval z_multi_result;
if (read_mbulk_header(redis_sock, &numElems) < 0) {
if (IS_ATOMIC(redis_sock)) {
RETVAL_FALSE;
} else {
add_next_index_bool(z_tab, 0);
}
return FAILURE;
}
array_init(&z_multi_result);
for (i = 0; i < numElems; ++i) {
if ((line = redis_sock_read(redis_sock, &len)) == NULL) {
add_next_index_bool(&z_multi_result, 0);
continue;
}
add_next_index_double(&z_multi_result, atof(line));
efree(line);
}
if (IS_ATOMIC(redis_sock)) {
RETVAL_ZVAL(&z_multi_result, 0, 1);
} else {
add_next_index_zval(z_tab, &z_multi_result);
}
return SUCCESS;
}
PHP_REDIS_API void
redis_mbulk_reply_loop(RedisSock *redis_sock, zval *z_tab, int count,
int unserialize)
{
zval z_unpacked;
char *line;
int i, len;
for (i = 0; i < count; ++i) {
if ((line = redis_sock_read(redis_sock, &len)) == NULL) {
add_next_index_bool(z_tab, 0);
continue;
}
/* We will attempt unserialization, if we're unserializing everything,
* or if we're unserializing keys and we're on a key, or we're
* unserializing values and we're on a value! */
int unwrap = (
(unserialize == UNSERIALIZE_ALL) ||
(unserialize == UNSERIALIZE_KEYS && i % 2 == 0) ||
(unserialize == UNSERIALIZE_VALS && i % 2 != 0)
);
if (unwrap && redis_unpack(redis_sock, line, len, &z_unpacked)) {
add_next_index_zval(z_tab, &z_unpacked);
} else {
add_next_index_stringl(z_tab, line, len);
}
efree(line);
}
}
static int
redis_mbulk_reply_zipped_raw_variant(RedisSock *redis_sock, zval *zret, int count) {
REDIS_REPLY_TYPE type;
char *key, *val;
int keylen, i;
zend_long lval;
double dval;
long vallen;
for (i = 0; i < count; i+= 2) {
/* Keys should always be bulk strings */
if ((key = redis_sock_read(redis_sock, &keylen)) == NULL)
return FAILURE;
/* This can vary */
if (redis_read_reply_type(redis_sock, &type, &vallen) < 0) {
efree(key);
return FAILURE;
}
if (type == TYPE_BULK) {
if (vallen > INT_MAX || (val = redis_sock_read_bulk_reply(redis_sock, (int)vallen)) == NULL) {
efree(key);
return FAILURE;
}
/* Possibly overkill, but provides really nice types */
switch (is_numeric_string(val, vallen, &lval, &dval, 0)) {
case IS_LONG:
add_assoc_long_ex(zret, key, keylen, lval);
break;
case IS_DOUBLE:
add_assoc_double_ex(zret, key, keylen, dval);
break;
default:
add_assoc_stringl_ex(zret, key, keylen, val, vallen);
}
efree(val);
} else if (type == TYPE_INT) {
add_assoc_long_ex(zret, key, keylen, (zend_long)vallen);
} else {
add_assoc_null_ex(zret, key, keylen);
}
efree(key);
}
return SUCCESS;
}
/* Specialized multibulk processing for HMGET where we need to pair requested
* keys with their returned values */
PHP_REDIS_API int redis_mbulk_reply_assoc(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx)
{
char *response;
int response_len;
int i, numElems;
zval *z_keys = ctx;
if (read_mbulk_header(redis_sock, &numElems) < 0) {
if (IS_ATOMIC(redis_sock)) {
RETVAL_FALSE;
} else {
add_next_index_bool(z_tab, 0);
}
goto failure;
}
zval z_multi_result;
array_init(&z_multi_result); /* pre-allocate array for multi's results. */
for(i = 0; i < numElems; ++i) {
zend_string *zstr = zval_get_string(&z_keys[i]);
response = redis_sock_read(redis_sock, &response_len);
if(response != NULL) {
zval z_unpacked;
if (redis_unpack(redis_sock, response, response_len, &z_unpacked)) {
add_assoc_zval_ex(&z_multi_result, ZSTR_VAL(zstr), ZSTR_LEN(zstr), &z_unpacked);
} else {
add_assoc_stringl_ex(&z_multi_result, ZSTR_VAL(zstr), ZSTR_LEN(zstr), response, response_len);
}
efree(response);
} else {
add_assoc_bool_ex(&z_multi_result, ZSTR_VAL(zstr), ZSTR_LEN(zstr), 0);
}
zend_string_release(zstr);
zval_dtor(&z_keys[i]);
}
efree(z_keys);
if (IS_ATOMIC(redis_sock)) {
RETVAL_ZVAL(&z_multi_result, 0, 1);
} else {
add_next_index_zval(z_tab, &z_multi_result);
}
return SUCCESS;
failure:
if (z_keys != NULL) {
for (i = 0; Z_TYPE(z_keys[i]) != IS_NULL; ++i) {
zval_dtor(&z_keys[i]);
}
efree(z_keys);
}
return FAILURE;
}
/**
* redis_sock_write
*/
PHP_REDIS_API int
redis_sock_write(RedisSock *redis_sock, char *cmd, size_t sz)
{
if (redis_check_eof(redis_sock, 0, 0) == 0 &&
redis_sock_write_raw(redis_sock, cmd, sz) == sz)
{
return sz;
}
return -1;
}
void
free_reply_callbacks(RedisSock *redis_sock)
{
fold_item *fi;
while (redis_sock->head != NULL) {
fi = redis_sock->head->next;
free(redis_sock->head);
redis_sock->head = fi;
}
redis_sock->current = NULL;
}
/**
* redis_free_socket
*/
PHP_REDIS_API void redis_free_socket(RedisSock *redis_sock)
{
int i;
if (redis_sock->prefix) {
zend_string_release(redis_sock->prefix);
}
if (redis_sock->pipeline_cmd) {
zend_string_release(redis_sock->pipeline_cmd);
}
if (redis_sock->err) {
zend_string_release(redis_sock->err);
}
if (redis_sock->persistent_id) {
zend_string_release(redis_sock->persistent_id);
}
if (redis_sock->host) {
zend_string_release(redis_sock->host);
}
for (i = 0; i < REDIS_SUBS_BUCKETS; ++i) {
if (redis_sock->subs[i]) {
zend_hash_destroy(redis_sock->subs[i]);
efree(redis_sock->subs[i]);
redis_sock->subs[i] = NULL;
}
}
redis_sock_free_auth(redis_sock);
free_reply_callbacks(redis_sock);
efree(redis_sock);
}
#ifdef HAVE_REDIS_LZ4
/* Implementation of CRC8 for our LZ4 checksum value */
static uint8_t crc8(unsigned char *input, size_t len) {
size_t i;
uint8_t crc = 0xFF;
while (len--) {
crc ^= *input++;
for (i = 0; i < 8; i++) {
if (crc & 0x80)
crc = (uint8_t)(crc << 1) ^ 0x31;
else
crc <<= 1;
}
}
return crc;
}
#endif
PHP_REDIS_API int
redis_compress(RedisSock *redis_sock, char **dst, size_t *dstlen, char *buf, size_t len) {
switch (redis_sock->compression) {
case REDIS_COMPRESSION_LZF:
#ifdef HAVE_REDIS_LZF
{
char *data;
uint32_t res;
double size;
/* preserve compatibility with PECL lzf_compress margin (greater of 4% and LZF_MARGIN) */
size = len + MIN(UINT_MAX - len, MAX(LZF_MARGIN, len / 25));
data = emalloc(size);
if ((res = lzf_compress(buf, len, data, size)) > 0) {
*dst = data;
*dstlen = res;
return 1;
}
efree(data);
}
#endif
break;
case REDIS_COMPRESSION_ZSTD:
#ifdef HAVE_REDIS_ZSTD
{
char *data;
size_t size;
int level;
if (redis_sock->compression_level < 1) {
#ifdef ZSTD_CLEVEL_DEFAULT
level = ZSTD_CLEVEL_DEFAULT;
#else
level = 3;
#endif
} else if (redis_sock->compression_level > ZSTD_maxCLevel()) {
level = ZSTD_maxCLevel();
} else {
level = redis_sock->compression_level;
}
size = ZSTD_compressBound(len);
data = emalloc(size);
size = ZSTD_compress(data, size, buf, len, level);
if (!ZSTD_isError(size)) {
*dst = erealloc(data, size);
*dstlen = size;
return 1;
}
efree(data);
}
#endif
break;
case REDIS_COMPRESSION_LZ4:
#ifdef HAVE_REDIS_LZ4
{
/* Compressing empty data is pointless */
if (len < 1)
break;
/* Compressing more than INT_MAX bytes would require multiple blocks */
if (len > INT_MAX) {
php_error_docref(NULL, E_WARNING,
"LZ4: compressing > %d bytes not supported", INT_MAX);
break;
}
int old_len = len, lz4len, lz4bound;
uint8_t crc = crc8((unsigned char*)&old_len, sizeof(old_len));
char *lz4buf, *lz4pos;
lz4bound = LZ4_compressBound(len);
lz4buf = emalloc(REDIS_LZ4_HDR_SIZE + lz4bound);
lz4pos = lz4buf;
/* Copy and move past crc8 length checksum */
memcpy(lz4pos, &crc, sizeof(crc));
lz4pos += sizeof(crc);
/* Copy and advance past length */
memcpy(lz4pos, &old_len, sizeof(old_len));
lz4pos += sizeof(old_len);
if (redis_sock->compression_level <= 0 || redis_sock->compression_level > REDIS_LZ4_MAX_CLEVEL) {
lz4len = LZ4_compress_default(buf, lz4pos, old_len, lz4bound);
} else {
lz4len = LZ4_compress_HC(buf, lz4pos, old_len, lz4bound, redis_sock->compression_level);
}
if (lz4len <= 0) {
efree(lz4buf);
break;
}
*dst = lz4buf;
*dstlen = lz4len + REDIS_LZ4_HDR_SIZE;
return 1;
}
#endif
break;
}
*dst = buf;
*dstlen = len;
return 0;
}
PHP_REDIS_API int
redis_uncompress(RedisSock *redis_sock, char **dst, size_t *dstlen, const char *src, size_t len) {
switch (redis_sock->compression) {
case REDIS_COMPRESSION_LZF:
#ifdef HAVE_REDIS_LZF
{
char *data = NULL;
uint32_t res;
int i;
if (len == 0)
break;
/* Grow our buffer until we succeed or get a non E2BIG error */
errno = E2BIG;
for (i = 2; errno == E2BIG; i *= 2) {
data = erealloc(data, len * i);
if ((res = lzf_decompress(src, len, data, len * i)) > 0) {
*dst = data;
*dstlen = res;
return 1;
}
}
efree(data);
break;
}
#endif
break;
case REDIS_COMPRESSION_ZSTD:
#ifdef HAVE_REDIS_ZSTD
{
char *data;
unsigned long long zlen;
zlen = ZSTD_getFrameContentSize(src, len);
if (zlen == ZSTD_CONTENTSIZE_ERROR || zlen == ZSTD_CONTENTSIZE_UNKNOWN || zlen > INT_MAX)
break;
data = emalloc(zlen);
*dstlen = ZSTD_decompress(data, zlen, src, len);
if (ZSTD_isError(*dstlen) || *dstlen != zlen) {
efree(data);
break;
}
*dst = data;
return 1;
}
#endif
break;
case REDIS_COMPRESSION_LZ4:
#ifdef HAVE_REDIS_LZ4
{
char *data;
int datalen;
uint8_t lz4crc;
/* We must have at least enough bytes for our header, and can't have more than
* INT_MAX + our header size. */
if (len < REDIS_LZ4_HDR_SIZE || len > INT_MAX + REDIS_LZ4_HDR_SIZE)
break;
/* Operate on copies in case our CRC fails */
const char *copy = src;
size_t copylen = len;
/* Read in our header bytes */
memcpy(&lz4crc, copy, sizeof(uint8_t));
copy += sizeof(uint8_t); copylen -= sizeof(uint8_t);
memcpy(&datalen, copy, sizeof(int));
copy += sizeof(int); copylen -= sizeof(int);
/* Make sure our CRC matches (TODO: Maybe issue a docref error?) */
if (crc8((unsigned char*)&datalen, sizeof(datalen)) != lz4crc)
break;
/* Finally attempt decompression */
data = emalloc(datalen);
if (LZ4_decompress_safe(copy, data, copylen, datalen) > 0) {
*dst = data;
*dstlen = datalen;
return 1;
}
efree(data);
}
#endif
break;
}
*dst = (char*)src;
*dstlen = len;
return 0;
}
PHP_REDIS_API int
redis_pack(RedisSock *redis_sock, zval *z, char **val, size_t *val_len) {
size_t tmplen;
int tmpfree;
char *tmp;
/* First serialize */
tmpfree = redis_serialize(redis_sock, z, &tmp, &tmplen);
/* Now attempt compression */
if (redis_compress(redis_sock, val, val_len, tmp, tmplen)) {
if (tmpfree) efree(tmp);
return 1;
}
return tmpfree;
}
PHP_REDIS_API int
redis_unpack(RedisSock *redis_sock, const char *src, int srclen, zval *zdst) {
size_t len;
char *buf;
/* Uncompress, then unserialize */
if (redis_uncompress(redis_sock, &buf, &len, src, srclen)) {
if (!redis_unserialize(redis_sock, buf, len, zdst)) {
ZVAL_STRINGL(zdst, buf, len);
}
efree(buf);
return 1;
}
return redis_unserialize(redis_sock, buf, len, zdst);
}
PHP_REDIS_API int
redis_serialize(RedisSock *redis_sock, zval *z, char **val, size_t *val_len)
{
php_serialize_data_t ht;
smart_str sstr = {0};
#ifdef HAVE_REDIS_IGBINARY
size_t sz;
uint8_t *val8;
#endif
*val = "";
*val_len = 0;
switch(redis_sock->serializer) {
case REDIS_SERIALIZER_NONE:
switch(Z_TYPE_P(z)) {
case IS_STRING:
*val = Z_STRVAL_P(z);
*val_len = Z_STRLEN_P(z);
break;
case IS_OBJECT:
*val = "Object";
*val_len = 6;
break;
case IS_ARRAY:
*val = "Array";
*val_len = 5;
break;
default: { /* copy */
zend_string *zstr = zval_get_string(z);
*val = estrndup(ZSTR_VAL(zstr), ZSTR_LEN(zstr));
*val_len = ZSTR_LEN(zstr);
zend_string_release(zstr);
return 1;
}
}
break;
case REDIS_SERIALIZER_PHP:
PHP_VAR_SERIALIZE_INIT(ht);
php_var_serialize(&sstr, z, &ht);
*val = estrndup(ZSTR_VAL(sstr.s), ZSTR_LEN(sstr.s));
*val_len = ZSTR_LEN(sstr.s);
smart_str_free(&sstr);
PHP_VAR_SERIALIZE_DESTROY(ht);
return 1;
case REDIS_SERIALIZER_MSGPACK:
#ifdef HAVE_REDIS_MSGPACK
php_msgpack_serialize(&sstr, z);
*val = estrndup(ZSTR_VAL(sstr.s), ZSTR_LEN(sstr.s));
*val_len = ZSTR_LEN(sstr.s);
smart_str_free(&sstr);
return 1;
#endif
break;
case REDIS_SERIALIZER_IGBINARY:
#ifdef HAVE_REDIS_IGBINARY
if(igbinary_serialize(&val8, (size_t *)&sz, z) == 0) {
*val = (char*)val8;
*val_len = sz;
return 1;
}
#endif
break;
case REDIS_SERIALIZER_JSON:
#ifdef HAVE_REDIS_JSON
php_json_encode(&sstr, z, PHP_JSON_OBJECT_AS_ARRAY);
*val = estrndup(ZSTR_VAL(sstr.s), ZSTR_LEN(sstr.s));
*val_len = ZSTR_LEN(sstr.s);
smart_str_free(&sstr);
return 1;
#endif
break;
EMPTY_SWITCH_DEFAULT_CASE()
}
return 0;
}
PHP_REDIS_API int
redis_unserialize(RedisSock* redis_sock, const char *val, int val_len,
zval *z_ret)
{
php_unserialize_data_t var_hash;
int ret = 0;
switch(redis_sock->serializer) {
case REDIS_SERIALIZER_NONE:
/* Nothing to do */
break;
case REDIS_SERIALIZER_PHP:
PHP_VAR_UNSERIALIZE_INIT(var_hash);
ret = php_var_unserialize(z_ret, (const unsigned char **)&val,
(const unsigned char *)val + val_len,
&var_hash);
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
break;
case REDIS_SERIALIZER_MSGPACK:
#ifdef HAVE_REDIS_MSGPACK
ret = !php_msgpack_unserialize(z_ret, (char *)val, (size_t)val_len);
#endif
break;
case REDIS_SERIALIZER_IGBINARY:
#ifdef HAVE_REDIS_IGBINARY
/*
* Check if the given string starts with an igbinary header.
*
* A modern igbinary string consists of the following format:
*
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
* | header (4) | type (1) | ... (n) | NUL (1) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
*
* With header being three zero bytes and one non-zero version
* specifier. At the time of this comment, there is only version
* 0x01 and 0x02, but newer versions will use subsequent
* values.
*
* Not all versions contain a trailing \x00 so don't check for that.
*/
if (val_len < 5 || memcmp(val, "\x00\x00\x00", 3) || val[3] < '\x01' || val[3] > '\x04')
{
/* This is most definitely not an igbinary string, so do
not try to unserialize this as one. */
break;
}
ret = !igbinary_unserialize((const uint8_t *)val, (size_t)val_len, z_ret);
#endif
break;
case REDIS_SERIALIZER_JSON:
#ifdef HAVE_REDIS_JSON
#if (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION < 1)
JSON_G(error_code) = PHP_JSON_ERROR_NONE;
php_json_decode(z_ret, (char*)val, val_len, 1, PHP_JSON_PARSER_DEFAULT_DEPTH);
ret = JSON_G(error_code) == PHP_JSON_ERROR_NONE;
#else
ret = !php_json_decode(z_ret, (char *)val, val_len, 1, PHP_JSON_PARSER_DEFAULT_DEPTH);
#endif
#endif
break;
EMPTY_SWITCH_DEFAULT_CASE()
}
return ret;
}
PHP_REDIS_API int
redis_key_prefix(RedisSock *redis_sock, char **key, size_t *key_len) {
int ret_len;
char *ret;
if (redis_sock->prefix == NULL) {
return 0;
}
ret_len = ZSTR_LEN(redis_sock->prefix) + *key_len;
ret = ecalloc(1 + ret_len, 1);
memcpy(ret, ZSTR_VAL(redis_sock->prefix), ZSTR_LEN(redis_sock->prefix));
memcpy(ret + ZSTR_LEN(redis_sock->prefix), *key, *key_len);
*key = ret;
*key_len = ret_len;
return 1;
}
/* This is very similar to PHP >= 7.4 zend_string_concat2 only we are taking
* two zend_string arguments rather than two char*, size_t pairs */
static zend_string *redis_zstr_concat(zend_string *prefix, zend_string *suffix) {
zend_string *res;
size_t len;
ZEND_ASSERT(prefix != NULL && suffix != NULL);
len = ZSTR_LEN(prefix) + ZSTR_LEN(suffix);
res = zend_string_alloc(len, 0);
memcpy(ZSTR_VAL(res), ZSTR_VAL(prefix), ZSTR_LEN(prefix));
memcpy(ZSTR_VAL(res) + ZSTR_LEN(prefix), ZSTR_VAL(suffix), ZSTR_LEN(suffix));
ZSTR_VAL(res)[len] = '\0';
return res;
}
PHP_REDIS_API zend_string *
redis_key_prefix_zval(RedisSock *redis_sock, zval *zv) {
zend_string *zstr, *dup;
zstr = zval_get_string(zv);
if (redis_sock->prefix == NULL)
return zstr;
dup = redis_zstr_concat(redis_sock->prefix, zstr);
zend_string_release(zstr);
return dup;
}
PHP_REDIS_API zend_string *
redis_key_prefix_zstr(RedisSock *redis_sock, zend_string *key) {
if (redis_sock->prefix == NULL)
return zend_string_copy(key);
return redis_zstr_concat(redis_sock->prefix, key);
}
/*
* Processing for variant reply types (think EVAL)
*/
PHP_REDIS_API int
redis_sock_gets(RedisSock *redis_sock, char *buf, int buf_size, size_t *line_size) {
// Handle EOF
if(-1 == redis_check_eof(redis_sock, 1, 0)) {
return -1;
}
if(redis_sock_get_line(redis_sock, buf, buf_size, line_size) == NULL) {
if (redis_sock->port < 0) {
snprintf(buf, buf_size, "read error on connection to %s", ZSTR_VAL(redis_sock->host));
} else {
snprintf(buf, buf_size, "read error on connection to %s:%d", ZSTR_VAL(redis_sock->host), redis_sock->port);
}
// Close our socket
redis_sock_disconnect(redis_sock, 1, 1);
// Throw a read error exception
REDIS_THROW_EXCEPTION(buf, 0);
return FAILURE;
}
/* We don't need \r\n */
*line_size-=2;
buf[*line_size]='\0';
/* Success! */
return 0;
}
PHP_REDIS_API int
redis_read_reply_type(RedisSock *redis_sock, REDIS_REPLY_TYPE *reply_type,
long *reply_info)
{
size_t nread;
// Make sure we haven't lost the connection, even trying to reconnect
if(-1 == redis_check_eof(redis_sock, 1, 0)) {
// Failure
*reply_type = EOF;
return -1;
}
// Attempt to read the reply-type byte
if((*reply_type = redis_sock_getc(redis_sock)) == EOF) {
REDIS_THROW_EXCEPTION( "socket error on read socket", 0);
return -1;
}
// If this is a BULK, MULTI BULK, or simply an INTEGER response, we can
// extract the value or size info here
if(*reply_type == TYPE_INT || *reply_type == TYPE_BULK ||
*reply_type == TYPE_MULTIBULK)
{
// Buffer to hold size information
char inbuf[255];
/* Read up to our newline */
if (redis_sock_get_line(redis_sock, inbuf, sizeof(inbuf), &nread) == NULL) {
return -1;
}
/* Set our size response */
*reply_info = atol(inbuf);
}
/* Success! */
return 0;
}
/*
* Read a single line response, having already consumed the reply-type byte
*/
static int
redis_read_variant_line(RedisSock *redis_sock, REDIS_REPLY_TYPE reply_type,
int as_string, zval *z_ret)
{
// Buffer to read our single line reply
char inbuf[4096];
size_t len;
/* Attempt to read our single line reply */
if(redis_sock_gets(redis_sock, inbuf, sizeof(inbuf), &len) < 0) {
return -1;
}
/* Throw exception on SYNC error otherwise just set error string */
if(reply_type == TYPE_ERR) {
redis_sock_set_err(redis_sock, inbuf, len);
redis_error_throw(redis_sock);
ZVAL_FALSE(z_ret);
} else if (as_string) {
ZVAL_STRINGL(z_ret, inbuf, len);
} else {
ZVAL_TRUE(z_ret);
}
return 0;
}
PHP_REDIS_API int
redis_read_variant_bulk(RedisSock *redis_sock, int size, zval *z_ret
)
{
// Attempt to read the bulk reply
char *bulk_resp = redis_sock_read_bulk_reply(redis_sock, size);
/* Set our reply to FALSE on failure, and the string on success */
if(bulk_resp == NULL) {
ZVAL_FALSE(z_ret);
return -1;
}
ZVAL_STRINGL(z_ret, bulk_resp, size);
efree(bulk_resp);
return 0;
}
PHP_REDIS_API int
redis_read_multibulk_recursive(RedisSock *redis_sock, long long elements, int status_strings,
zval *z_ret)
{
long reply_info;
REDIS_REPLY_TYPE reply_type;
zval z_subelem;
// Iterate while we have elements
while(elements > 0) {
// Attempt to read our reply type
if(redis_read_reply_type(redis_sock, &reply_type, &reply_info
) < 0)
{
zend_throw_exception_ex(redis_exception_ce, 0,
"protocol error, couldn't parse MULTI-BULK response\n");
return FAILURE;
}
// Switch on our reply-type byte
switch(reply_type) {
case TYPE_ERR:
case TYPE_LINE:
redis_read_variant_line(redis_sock, reply_type, status_strings,
&z_subelem);
add_next_index_zval(z_ret, &z_subelem);
break;
case TYPE_INT:
// Add our long value
add_next_index_long(z_ret, reply_info);
break;
case TYPE_BULK:
// Init a zval for our bulk response, read and add it
redis_read_variant_bulk(redis_sock, reply_info, &z_subelem);
add_next_index_zval(z_ret, &z_subelem);
break;
case TYPE_MULTIBULK:
if (reply_info < 0 && redis_sock->null_mbulk_as_null) {
add_next_index_null(z_ret);
} else {
array_init(&z_subelem);
if (reply_info > 0) {
redis_read_multibulk_recursive(redis_sock, reply_info, status_strings, &z_subelem);
}
add_next_index_zval(z_ret, &z_subelem);
}
break;
default:
// Stop the compiler from whinging
break;
}
/* Decrement our element counter */
elements--;
}
return 0;
}
static int
variant_reply_generic(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
int status_strings, int null_mbulk_as_null,
zval *z_tab, void *ctx)
{
// Reply type, and reply size vars
REDIS_REPLY_TYPE reply_type;
long reply_info;
zval z_ret;
// Attempt to read our header
if(redis_read_reply_type(redis_sock,&reply_type,&reply_info) < 0) {
return -1;
}
/* Switch based on our top level reply type */
switch(reply_type) {
case TYPE_ERR:
case TYPE_LINE:
redis_read_variant_line(redis_sock, reply_type, status_strings, &z_ret);
break;
case TYPE_INT:
ZVAL_LONG(&z_ret, reply_info);
break;
case TYPE_BULK:
redis_read_variant_bulk(redis_sock, reply_info, &z_ret);
break;
case TYPE_MULTIBULK:
if (reply_info > -1) {
array_init(&z_ret);
redis_read_multibulk_recursive(redis_sock, reply_info, status_strings, &z_ret);
} else {
if (null_mbulk_as_null) {
ZVAL_NULL(&z_ret);
} else {
array_init(&z_ret);
}
}
break;
default:
zend_throw_exception_ex(redis_exception_ce, 0,
"protocol error, got '%c' as reply-type byte\n", reply_type);
return FAILURE;
}
if (IS_ATOMIC(redis_sock)) {
/* Set our return value */
RETVAL_ZVAL(&z_ret, 0, 1);
} else {
add_next_index_zval(z_tab, &z_ret);
}
/* Success */
return 0;
}
PHP_REDIS_API int
redis_read_raw_variant_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
zval *z_tab, void *ctx)
{
return variant_reply_generic(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock,
redis_sock->reply_literal,
redis_sock->null_mbulk_as_null,
z_tab, ctx);
}
PHP_REDIS_API int
redis_read_variant_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
zval *z_tab, void *ctx)
{
return variant_reply_generic(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, 0,
redis_sock->null_mbulk_as_null, z_tab, ctx);
}
PHP_REDIS_API int
redis_read_variant_reply_strings(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
zval *z_tab, void *ctx)
{
return variant_reply_generic(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, 1, 0, z_tab, ctx);
}
PHP_REDIS_API
int redis_extract_auth_info(zval *ztest, zend_string **user, zend_string **pass) {
zval *zv;
HashTable *ht;
int num;
/* The user may wish to send us something like [NULL, 'password'] or
* [false, 'password'] so don't convert NULL or FALSE into "". */
#define TRY_SET_AUTH_ARG(zv, ppzstr) \
do { \
if (Z_TYPE_P(zv) != IS_NULL && Z_TYPE_P(zv) != IS_FALSE) { \
*(ppzstr) = zval_get_string(zv); \
} \
} while (0)
/* Null out user and password */
*user = *pass = NULL;
/* User passed nothing */
if (ztest == NULL)
return FAILURE;
/* Handle a non-array first */
if (Z_TYPE_P(ztest) != IS_ARRAY) {
TRY_SET_AUTH_ARG(ztest, pass);
return SUCCESS;
}
/* Handle the array case */
ht = Z_ARRVAL_P(ztest);
num = zend_hash_num_elements(ht);
/* Something other than one or two entries makes no sense */
if (num != 1 && num != 2) {
php_error_docref(NULL, E_WARNING, "When passing an array as auth it must have one or two elements!");
return FAILURE;
}
if (num == 2) {
if ((zv = REDIS_HASH_STR_FIND_STATIC(ht, "user")) ||
(zv = zend_hash_index_find(ht, 0)))
{
TRY_SET_AUTH_ARG(zv, user);
}
if ((zv = REDIS_HASH_STR_FIND_STATIC(ht, "pass")) ||
(zv = zend_hash_index_find(ht, 1)))
{
TRY_SET_AUTH_ARG(zv, pass);
}
} else if ((zv = REDIS_HASH_STR_FIND_STATIC(ht, "pass")) ||
(zv = zend_hash_index_find(ht, 0)))
{
TRY_SET_AUTH_ARG(zv, pass);
}
/* If we at least have a password, we're good */
if (*pass != NULL)
return SUCCESS;
/* Failure, clean everything up so caller doesn't need to care */
if (*user) zend_string_release(*user);
*user = NULL;
return FAILURE;
}
/* Helper methods to extract configuration settings from a hash table */
zval *redis_hash_str_find_type(HashTable *ht, const char *key, int keylen, int type) {
zval *zv = zend_hash_str_find(ht, key, keylen);
if (zv == NULL || Z_TYPE_P(zv) != type)
return NULL;
return zv;
}
void redis_conf_double(HashTable *ht, const char *key, int keylen, double *dval) {
zval *zv = zend_hash_str_find(ht, key, keylen);
if (zv == NULL)
return;
*dval = zval_get_double(zv);
}
void redis_conf_bool(HashTable *ht, const char *key, int keylen, int *ival) {
zend_string *zstr = NULL;
redis_conf_string(ht, key, keylen, &zstr);
if (zstr == NULL)
return;
*ival = zend_string_equals_literal_ci(zstr, "true") ||
zend_string_equals_literal_ci(zstr, "yes") ||
zend_string_equals_literal_ci(zstr, "1");
zend_string_release(zstr);
}
void redis_conf_zend_bool(HashTable *ht, const char *key, int keylen, zend_bool *bval) {
zval *zv = zend_hash_str_find(ht, key, keylen);
if (zv == NULL)
return;
*bval = zend_is_true(zv);
}
void redis_conf_long(HashTable *ht, const char *key, int keylen, zend_long *lval) {
zval *zv = zend_hash_str_find(ht, key, keylen);
if (zv == NULL)
return;
*lval = zval_get_long(zv);
}
void redis_conf_int(HashTable *ht, const char *key, int keylen, int *ival) {
zval *zv = zend_hash_str_find(ht, key, keylen);
if (zv == NULL)
return;
*ival = zval_get_long(zv);
}
void redis_conf_string(HashTable *ht, const char *key, size_t keylen,
zend_string **sval)
{
zval *zv = zend_hash_str_find(ht, key, keylen);
if (zv == NULL)
return;
*sval = zval_get_string(zv);
}
void redis_conf_zval(HashTable *ht, const char *key, size_t keylen, zval *zret,
int copy, int dtor)
{
zval *zv = zend_hash_str_find(ht, key, keylen);
if (zv == NULL)
return;
ZVAL_ZVAL(zret, zv, copy, dtor);
}
void redis_conf_auth(HashTable *ht, const char *key, size_t keylen,
zend_string **user, zend_string **pass)
{
zval *zv = zend_hash_str_find(ht, key, keylen);
if (zv == NULL)
return;
redis_extract_auth_info(zv, user, pass);
}
/* vim: set tabstop=4 softtabstop=4 expandtab shiftwidth=4: */
redis-6.0.2/library.h 0000644 0001750 0000012 00000040000 14515245367 015227 0 ustar pyatsukhnenko wheel #ifndef REDIS_LIBRARY_H
#define REDIS_LIBRARY_H
/* Non cluster command helper */
#define REDIS_SPPRINTF(ret, kw, fmt, ...) \
redis_spprintf(redis_sock, NULL, ret, kw, fmt, ##__VA_ARGS__)
#define REDIS_CMD_APPEND_SSTR_STATIC(sstr, str) \
redis_cmd_append_sstr(sstr, str, sizeof(str)-1);
#define REDIS_CMD_APPEND_SSTR_OPT_STATIC(sstr, opt, str) \
if (opt) REDIS_CMD_APPEND_SSTR_STATIC(sstr, str);
#define REDIS_CMD_INIT_SSTR_STATIC(sstr, argc, keyword) \
redis_cmd_init_sstr(sstr, argc, keyword, sizeof(keyword)-1);
#define REDIS_THROW_EXCEPTION(msg, code) \
zend_throw_exception(redis_exception_ce, (msg), code)
#define CLUSTER_THROW_EXCEPTION(msg, code) \
zend_throw_exception(redis_cluster_exception_ce, (msg), code)
#define redis_sock_write_sstr(redis_sock, sstr) \
redis_sock_write(redis_sock, (sstr)->c, (sstr)->len)
#if PHP_VERSION_ID < 80000
#define redis_hash_fetch_ops(zstr) php_hash_fetch_ops(ZSTR_VAL((zstr)), ZSTR_LEN((zstr)))
/* use RedisException when ValueError not available */
#define REDIS_VALUE_EXCEPTION(m) REDIS_THROW_EXCEPTION(m, 0)
#define RETURN_THROWS() RETURN_FALSE
#else
#define redis_hash_fetch_ops(zstr) php_hash_fetch_ops(zstr)
#define REDIS_VALUE_EXCEPTION(m) zend_value_error(m)
#endif
void redis_register_persistent_resource(zend_string *id, void *ptr, int le_id);
void free_reply_callbacks(RedisSock *redis_sock);
PHP_REDIS_API int redis_extract_auth_info(zval *ztest, zend_string **user, zend_string **pass);
int redis_cmd_init_sstr(smart_string *str, int num_args, char *keyword, int keyword_len);
int redis_cmd_append_sstr(smart_string *str, char *append, int append_len);
int redis_cmd_append_sstr_int(smart_string *str, int append);
int redis_cmd_append_sstr_long(smart_string *str, long append);
int redis_cmd_append_sstr_i64(smart_string *str, int64_t append);
int redis_cmd_append_sstr_dbl(smart_string *str, double value);
int redis_cmd_append_sstr_zstr(smart_string *str, zend_string *zstr);
int redis_cmd_append_sstr_zval(smart_string *str, zval *z, RedisSock *redis_sock);
int redis_cmd_append_sstr_key(smart_string *str, char *key, size_t len, RedisSock *redis_sock, short *slot);
int redis_cmd_append_sstr_key_zstr(smart_string *str, zend_string *key, RedisSock *redis_sock, short *slot);
int redis_cmd_append_sstr_key_zval(smart_string *dst, zval *zv, RedisSock *redis_sock, short *slot);
int redis_cmd_append_sstr_key_long(smart_string *dst, zend_long lval, RedisSock *redis_sock, short *slot);
int redis_cmd_append_sstr_arrkey(smart_string *cmd, zend_string *kstr, zend_ulong idx);
PHP_REDIS_API int redis_spprintf(RedisSock *redis_sock, short *slot, char **ret, char *kw, char *fmt, ...);
PHP_REDIS_API zend_string *redis_pool_spprintf(RedisSock *redis_sock, char *fmt, ...);
PHP_REDIS_API char *redis_sock_read(RedisSock *redis_sock, int *buf_len);
PHP_REDIS_API int redis_sock_gets(RedisSock *redis_sock, char *buf, int buf_size, size_t* line_len);
PHP_REDIS_API int redis_1_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_long_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval* z_tab, void *ctx);
typedef void (*SuccessCallback)(RedisSock *redis_sock);
PHP_REDIS_API int redis_boolean_response_impl(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx, SuccessCallback success_callback);
PHP_REDIS_API int redis_boolean_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_bulk_double_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_string_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_ping_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_info_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_config_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_zrange_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API void redis_parse_info_response(char *response, zval *z_ret);
PHP_REDIS_API void redis_parse_client_list_response(char *response, zval *z_ret);
PHP_REDIS_API int redis_type_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API RedisSock* redis_sock_create(char *host, int host_len, int port, double timeout, double read_timeout, int persistent, char *persistent_id, long retry_interval);
PHP_REDIS_API int redis_sock_configure(RedisSock *redis_sock, HashTable *opts);
PHP_REDIS_API int redis_sock_connect(RedisSock *redis_sock);
PHP_REDIS_API int redis_sock_server_open(RedisSock *redis_sock);
PHP_REDIS_API int redis_sock_auth(RedisSock *redis_sock);
PHP_REDIS_API char *redis_sock_auth_cmd(RedisSock *redis_sock, int *cmdlen);
PHP_REDIS_API void redis_sock_set_auth(RedisSock *redis_sock, zend_string *user, zend_string *pass);
PHP_REDIS_API void redis_sock_set_auth_zval(RedisSock *redis_sock, zval *zv);
PHP_REDIS_API void redis_sock_free_auth(RedisSock *redis_sock);
PHP_REDIS_API int redis_sock_disconnect(RedisSock *redis_sock, int force, int is_reset_mode);
PHP_REDIS_API zval *redis_sock_read_multibulk_reply_zval(RedisSock *redis_sock, zval *z_tab);
PHP_REDIS_API int redis_sock_read_single_line(RedisSock *redis_sock, char *buffer,
size_t buflen, size_t *linelen, int set_err);
PHP_REDIS_API char *redis_sock_read_bulk_reply(RedisSock *redis_sock, int bytes);
PHP_REDIS_API int redis_sock_read_multibulk_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *_z_tab, void *ctx);
PHP_REDIS_API void redis_mbulk_reply_loop(RedisSock *redis_sock, zval *z_tab, int count, int unserialize);
PHP_REDIS_API int redis_mbulk_reply_raw(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_mbulk_reply_zipped_raw(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_mbulk_reply_zipped_vals(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_mbulk_reply_zipped_keys_int(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_mbulk_reply_zipped_keys_dbl(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_mbulk_reply_assoc(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_mbulk_reply_double(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_sock_read_scan_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, REDIS_SCAN_TYPE type, zend_long *iter);
PHP_REDIS_API int redis_xrange_reply(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_xread_reply(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_xclaim_reply(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_read_xclaim_reply(
RedisSock *redis_sock, int count, int is_xautoclaim, zval *rv);
PHP_REDIS_API int redis_xinfo_reply(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_pubsub_response(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_subscribe_response(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_unsubscribe_response(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_sock_write(RedisSock *redis_sock, char *cmd, size_t sz);
PHP_REDIS_API int redis_check_eof(RedisSock *redis_sock, zend_bool no_retry, zend_bool no_throw);
PHP_REDIS_API RedisSock *redis_sock_get(zval *id, int nothrow);
PHP_REDIS_API void redis_free_socket(RedisSock *redis_sock);
PHP_REDIS_API void redis_sock_set_err(RedisSock *redis_sock, const char *msg, int msg_len);
PHP_REDIS_API int redis_sock_set_stream_context(RedisSock *redis_sock, zval *options);
PHP_REDIS_API int redis_sock_set_backoff(RedisSock *redis_sock, zval *options);
PHP_REDIS_API int
redis_serialize(RedisSock *redis_sock, zval *z, char **val, size_t *val_len);
PHP_REDIS_API int
redis_key_prefix(RedisSock *redis_sock, char **key, size_t *key_len);
PHP_REDIS_API zend_string*
redis_key_prefix_zval(RedisSock *redis_sock, zval *zv);
PHP_REDIS_API zend_string *
redis_key_prefix_zstr(RedisSock *redis_sock, zend_string *key);
PHP_REDIS_API int
redis_unserialize(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret);
PHP_REDIS_API int
redis_compress(RedisSock *redis_sock, char **dst, size_t *dstlen, char *buf, size_t len);
PHP_REDIS_API int
redis_uncompress(RedisSock *redis_sock, char **dst, size_t *dstlen, const char *src, size_t len);
PHP_REDIS_API int redis_pack(RedisSock *redis_sock, zval *z, char **val, size_t *val_len);
PHP_REDIS_API int redis_unpack(RedisSock *redis_sock, const char *val, int val_len, zval *z_ret);
PHP_REDIS_API int
redis_read_stream_messages(RedisSock *redis_sock, int count, zval *z_ret);
PHP_REDIS_API int
redis_read_stream_messages_multi(RedisSock *redis_sock, int count, zval *z_ret);
PHP_REDIS_API int
redis_read_xinfo_response(RedisSock *redis_sock, zval *z_ret, int elements);
PHP_REDIS_API int
redis_mpop_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
zval *z_tab, void *ctx);
PHP_REDIS_API int
redis_read_mpop_response(RedisSock *redis_sock, zval *zdst, int elements, void *ctx);
/* Specialized ACL reply handlers */
PHP_REDIS_API int redis_acl_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_read_acl_getuser_reply(RedisSock *redis_sock, zval *zret, long len);
PHP_REDIS_API int redis_acl_getuser_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_read_acl_log_reply(RedisSock *redis_sock, zval *zret, long count);
PHP_REDIS_API int redis_acl_log_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
/*
* Variant Read methods, mostly to implement eval
*/
PHP_REDIS_API int redis_read_reply_type(RedisSock *redis_sock, REDIS_REPLY_TYPE *reply_type, long *reply_info);
PHP_REDIS_API int redis_read_variant_bulk(RedisSock *redis_sock, int size, zval *z_ret);
PHP_REDIS_API int redis_read_multibulk_recursive(RedisSock *redis_sock, long long elements, int status_strings, zval *z_ret);
PHP_REDIS_API int redis_read_variant_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_read_raw_variant_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_read_variant_reply_strings(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_client_list_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_zadd_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_zrandmember_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_zdiff_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_set_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_read_geosearch_response(zval *zdst, RedisSock *redis_sock, long long elements, int with_aux_data);
PHP_REDIS_API int redis_geosearch_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_hrandfield_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_pop_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_srandmember_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_lpos_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_object_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_read_lpos_response(zval *zdst, RedisSock *redis_sock, char reply_type, long long elements, void *ctx);
PHP_REDIS_API int redis_client_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_function_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_command_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_select_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
/* Helper methods to get configuration values from a HashTable. */
#define REDIS_HASH_STR_FIND_STATIC(ht, sstr) \
zend_hash_str_find(ht, sstr, sizeof(sstr) - 1)
#define REDIS_HASH_STR_FIND_TYPE_STATIC(ht, sstr, type) \
redis_hash_str_find_type(ht, sstr, sizeof(sstr) - 1, type)
#define REDIS_CONF_DOUBLE_STATIC(ht, sstr, dval) \
redis_conf_double(ht, sstr, sizeof(sstr) - 1, dval)
#define REDIS_CONF_BOOL_STATIC(ht, sstr, rval) \
redis_conf_bool(ht, sstr, sizeof(sstr) - 1, rval)
#define REDIS_CONF_ZEND_BOOL_STATIC(ht, sstr, bval) \
redis_conf_zend_bool(ht, sstr, sizeof(sstr) - 1, bval)
#define REDIS_CONF_LONG_STATIC(ht, sstr, lval) \
redis_conf_long(ht, sstr, sizeof(sstr) - 1, lval)
#define REDIS_CONF_INT_STATIC(ht, sstr, ival) \
redis_conf_int(ht, sstr, sizeof(sstr) - 1, ival)
#define REDIS_CONF_STRING_STATIC(ht, sstr, sval) \
redis_conf_string(ht, sstr, sizeof(sstr) - 1, sval)
#define REDIS_CONF_ZVAL_STATIC(ht, sstr, zret, copy, dtor) \
redis_conf_zval(ht, sstr, sizeof(sstr) - 1, zret, copy, dtor)
#define REDIS_CONF_AUTH_STATIC(ht, sstr, user, pass) \
redis_conf_auth(ht, sstr, sizeof(sstr) - 1, user, pass)
zval *redis_hash_str_find_type(HashTable *ht, const char *key, int keylen, int type);
void redis_conf_double(HashTable *ht, const char *key, int keylen, double *dval);
void redis_conf_bool(HashTable *ht, const char *key, int keylen, int *bval);
void redis_conf_zend_bool(HashTable *ht, const char *key, int keylen, zend_bool *bval);
void redis_conf_long(HashTable *ht, const char *key, int keylen, zend_long *lval);
void redis_conf_int(HashTable *ht, const char *key, int keylen, int *ival);
void redis_conf_string(HashTable *ht, const char *key, size_t keylen, zend_string **sval);
void redis_conf_zval(HashTable *ht, const char *key, size_t keylen, zval *zret, int copy, int dtor);
void redis_conf_auth(HashTable *ht, const char *key, size_t keylen, zend_string **user, zend_string **pass);
static inline char *redis_sock_get_line(RedisSock *redis_sock, char *buf, size_t buf_size, size_t *nread) {
char *res;
res = php_stream_get_line(redis_sock->stream, buf, buf_size, nread);
if (res != NULL)
redis_sock->rxBytes += *nread;
return res;
}
static inline char redis_sock_getc(RedisSock *redis_sock) {
char res;
res = php_stream_getc(redis_sock->stream);
if (res != EOF)
redis_sock->rxBytes++;
return res;
}
static inline ssize_t redis_sock_read_raw(RedisSock *redis_sock, char *buf, size_t buf_size) {
ssize_t nread;
nread = php_stream_read(redis_sock->stream, buf, buf_size);
if (nread > 0)
redis_sock->rxBytes += nread;
return nread;
}
static inline ssize_t redis_sock_write_raw(RedisSock *redis_sock, const char *buf, size_t buf_size) {
ssize_t nwritten;
nwritten = php_stream_write(redis_sock->stream, buf, buf_size);
if (nwritten > 0)
redis_sock->txBytes += nwritten;
return nwritten;
}
static inline char *redis_sock_gets_raw(RedisSock *redis_sock, char *buf, size_t buf_size) {
size_t nread;
return redis_sock_get_line(redis_sock, buf, buf_size, &nread);
}
#endif
redis-6.0.2/php_redis.h 0000644 0001750 0000012 00000004554 14515245367 015556 0 ustar pyatsukhnenko wheel /*
+----------------------------------------------------------------------+
| Copyright (c) 1997-2009 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Original author: Alfonso Jimenez |
| Maintainer: Nicolas Favre-Felix |
| Maintainer: Michael Grunder |
| Maintainer: Nasreddine Bouafif |
+----------------------------------------------------------------------+
*/
#include "common.h"
#ifndef PHP_REDIS_H
#define PHP_REDIS_H
/* phpredis version */
#define PHP_REDIS_VERSION "6.0.2"
/* For convenience we store the salt as a printable hex string which requires 2
* characters per byte + 1 for the NULL terminator */
#define REDIS_SALT_BYTES 32
#define REDIS_SALT_SIZE ((2 * REDIS_SALT_BYTES) + 1)
ZEND_BEGIN_MODULE_GLOBALS(redis)
char salt[REDIS_SALT_SIZE];
ZEND_END_MODULE_GLOBALS(redis)
ZEND_EXTERN_MODULE_GLOBALS(redis)
#define REDIS_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(redis, v)
#ifdef ZTS
#include "TSRM.h"
#endif
PHP_MINIT_FUNCTION(redis);
PHP_MSHUTDOWN_FUNCTION(redis);
PHP_MINFO_FUNCTION(redis);
PHP_REDIS_API int redis_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent);
PHP_REDIS_API int redis_response_enqueued(RedisSock *redis_sock);
PHP_REDIS_API int redis_sock_read_multibulk_multi_reply_loop(
INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab);
extern zend_module_entry redis_module_entry;
#define redis_module_ptr &redis_module_entry
#define phpext_redis_ptr redis_module_ptr
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
redis-6.0.2/redis.c 0000644 0001750 0000012 00000245434 14515245367 014706 0 ustar pyatsukhnenko wheel /* -*- Mode: C; tab-width: 4 -*- */
/*
+----------------------------------------------------------------------+
| Copyright (c) 1997-2009 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Original author: Alfonso Jimenez |
| Maintainer: Nicolas Favre-Felix |
| Maintainer: Nasreddine Bouafif |
| Maintainer: Michael Grunder |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php_redis.h"
#include "redis_array.h"
#include "redis_cluster.h"
#include "redis_commands.h"
#include "redis_sentinel.h"
#include
#include
#include
#include
#include
#ifdef PHP_SESSION
#include
#endif
#include "library.h"
#ifdef HAVE_REDIS_ZSTD
#include
#endif
#ifdef HAVE_REDIS_LZ4
#include
#endif
#ifdef PHP_SESSION
extern ps_module ps_mod_redis;
extern ps_module ps_mod_redis_cluster;
#endif
zend_class_entry *redis_ce;
zend_class_entry *redis_exception_ce;
#if PHP_VERSION_ID < 80000
#include "redis_legacy_arginfo.h"
#else
#include "zend_attributes.h"
#include "redis_arginfo.h"
#endif
extern const zend_function_entry *redis_get_methods(void)
{
return class_Redis_methods;
}
extern int le_cluster_slot_cache;
int le_redis_pconnect;
PHP_INI_BEGIN()
/* redis arrays */
PHP_INI_ENTRY("redis.arrays.algorithm", "", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.arrays.auth", "", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.arrays.autorehash", "0", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.arrays.connecttimeout", "0", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.arrays.distributor", "", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.arrays.functions", "", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.arrays.hosts", "", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.arrays.index", "0", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.arrays.lazyconnect", "0", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.arrays.names", "", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.arrays.pconnect", "0", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.arrays.previous", "", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.arrays.readtimeout", "0", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.arrays.retryinterval", "0", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.arrays.consistent", "0", PHP_INI_ALL, NULL)
/* redis cluster */
PHP_INI_ENTRY("redis.clusters.cache_slots", "0", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.clusters.auth", "", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.clusters.persistent", "0", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.clusters.read_timeout", "0", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.clusters.seeds", "", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.clusters.timeout", "0", PHP_INI_ALL, NULL)
/* redis pconnect */
PHP_INI_ENTRY("redis.pconnect.pooling_enabled", "1", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.pconnect.connection_limit", "0", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.pconnect.echo_check_liveness", "1", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.pconnect.pool_detect_dirty", "0", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.pconnect.pool_poll_timeout", "0", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.pconnect.pool_pattern", "", PHP_INI_ALL, NULL)
/* redis session */
PHP_INI_ENTRY("redis.session.locking_enabled", "0", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.session.lock_expire", "0", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.session.lock_retries", "100", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.session.lock_wait_time", "20000", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.session.early_refresh", "0", PHP_INI_ALL, NULL)
PHP_INI_END()
static const zend_module_dep redis_deps[] = {
#ifdef HAVE_REDIS_IGBINARY
ZEND_MOD_REQUIRED("igbinary")
#endif
#ifdef HAVE_REDIS_MSGPACK
ZEND_MOD_REQUIRED("msgpack")
#endif
#ifdef HAVE_REDIS_JSON
ZEND_MOD_REQUIRED("json")
#endif
#ifdef PHP_SESSION
ZEND_MOD_REQUIRED("session")
#endif
ZEND_MOD_END
};
ZEND_DECLARE_MODULE_GLOBALS(redis)
zend_module_entry redis_module_entry = {
STANDARD_MODULE_HEADER_EX,
NULL,
redis_deps,
"redis",
NULL,
PHP_MINIT(redis),
NULL,
NULL,
NULL,
PHP_MINFO(redis),
PHP_REDIS_VERSION,
PHP_MODULE_GLOBALS(redis),
NULL,
NULL,
NULL,
STANDARD_MODULE_PROPERTIES_EX
};
#ifdef COMPILE_DL_REDIS
ZEND_GET_MODULE(redis)
#endif
zend_object_handlers redis_object_handlers;
/* Send a static DISCARD in case we're in MULTI mode. */
static int
redis_send_discard(RedisSock *redis_sock)
{
char *resp;
int resp_len, result = FAILURE;
/* send our DISCARD command */
if (redis_sock_write(redis_sock, ZEND_STRL(RESP_DISCARD_CMD)) >= 0 &&
(resp = redis_sock_read(redis_sock,&resp_len)) != NULL)
{
/* success if we get OK */
result = (resp_len == 3 && strncmp(resp,"+OK", 3) == 0) ? SUCCESS:FAILURE;
/* free our response */
efree(resp);
}
/* return success/failure */
return result;
}
/* Passthru for destroying cluster cache */
static void cluster_cache_dtor(zend_resource *rsrc) {
if (rsrc->ptr) {
cluster_cache_free(rsrc->ptr);
}
}
void
free_redis_object(zend_object *object)
{
redis_object *redis = PHPREDIS_GET_OBJECT(redis_object, object);
zend_object_std_dtor(&redis->std);
if (redis->sock) {
redis_sock_disconnect(redis->sock, 0, 1);
redis_free_socket(redis->sock);
}
}
zend_object *
create_redis_object(zend_class_entry *ce)
{
redis_object *redis = ecalloc(1, sizeof(redis_object) + zend_object_properties_size(ce));
redis->sock = NULL;
zend_object_std_init(&redis->std, ce);
object_properties_init(&redis->std, ce);
memcpy(&redis_object_handlers, zend_get_std_object_handlers(), sizeof(redis_object_handlers));
redis_object_handlers.offset = XtOffsetOf(redis_object, std);
redis_object_handlers.free_obj = free_redis_object;
redis->std.handlers = &redis_object_handlers;
return &redis->std;
}
static zend_always_inline RedisSock *
redis_sock_get_instance(zval *id, int no_throw)
{
redis_object *redis;
if (Z_TYPE_P(id) == IS_OBJECT) {
redis = PHPREDIS_ZVAL_GET_OBJECT(redis_object, id);
if (redis->sock) {
return redis->sock;
}
}
// Throw an exception unless we've been requested not to
if (!no_throw) {
REDIS_THROW_EXCEPTION("Redis server went away", 0);
}
return NULL;
}
/**
* redis_sock_get
*/
PHP_REDIS_API RedisSock *
redis_sock_get(zval *id, int no_throw)
{
RedisSock *redis_sock;
if ((redis_sock = redis_sock_get_instance(id, no_throw)) == NULL) {
return NULL;
}
if (redis_sock_server_open(redis_sock) < 0) {
if (!no_throw) {
char *errmsg = NULL;
if (redis_sock->port < 0) {
spprintf(&errmsg, 0, "Redis server %s went away", ZSTR_VAL(redis_sock->host));
} else {
spprintf(&errmsg, 0, "Redis server %s:%d went away", ZSTR_VAL(redis_sock->host), redis_sock->port);
}
REDIS_THROW_EXCEPTION(errmsg, 0);
efree(errmsg);
}
return NULL;
}
return redis_sock;
}
/**
* redis_sock_get_direct
* Returns our attached RedisSock pointer if we're connected
*/
PHP_REDIS_API RedisSock *redis_sock_get_connected(INTERNAL_FUNCTION_PARAMETERS) {
zval *object;
RedisSock *redis_sock;
// If we can't grab our object, or get a socket, or we're not connected,
// return NULL
if((zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
&object, redis_ce) == FAILURE) ||
(redis_sock = redis_sock_get(object, 1)) == NULL ||
redis_sock->status < REDIS_SOCK_STATUS_CONNECTED)
{
return NULL;
}
/* Return our socket */
return redis_sock;
}
static ZEND_RSRC_DTOR_FUNC(redis_connections_pool_dtor)
{
if (res->ptr) {
ConnectionPool *p = res->ptr;
zend_llist_destroy(&p->list);
pefree(res->ptr, 1);
}
}
static void redis_random_hex_bytes(char *dst, size_t dstsize) {
char chunk[9], *ptr = dst;
ssize_t rem = dstsize, len, clen;
size_t bytes;
/* We need two characters per hex byte */
bytes = dstsize / 2;
zend_string *s = zend_string_alloc(bytes, 0);
/* First try to have PHP generate the bytes */
if (php_random_bytes_silent(ZSTR_VAL(s), bytes) == SUCCESS) {
php_hash_bin2hex(dst, (unsigned char *)ZSTR_VAL(s), bytes);
zend_string_release(s);
return;
}
/* PHP shouldn't have failed, but generate manually if it did. */
while (rem > 0) {
clen = snprintf(chunk, sizeof(chunk), "%08x", rand());
len = rem >= clen ? clen : rem;
memcpy(ptr, chunk, len);
ptr += len; rem -= len;
}
zend_string_release(s);
}
/**
* PHP_MINIT_FUNCTION
*/
PHP_MINIT_FUNCTION(redis)
{
struct timeval tv;
/* Seed random generator (for RedisCluster failover) */
gettimeofday(&tv, NULL);
srand(tv.tv_usec * tv.tv_sec);
/* Generate our random salt */
redis_random_hex_bytes(REDIS_G(salt), sizeof(REDIS_G(salt)) - 1);
REDIS_G(salt)[sizeof(REDIS_G(salt)) - 1] = '\0';
REGISTER_INI_ENTRIES();
/* Redis class */
redis_ce = register_class_Redis();
redis_ce->create_object = create_redis_object;
/* RedisArray class */
ZEND_MINIT(redis_array)(INIT_FUNC_ARGS_PASSTHRU);
/* RedisCluster class */
ZEND_MINIT(redis_cluster)(INIT_FUNC_ARGS_PASSTHRU);
/* RedisSentinel class */
ZEND_MINIT(redis_sentinel)(INIT_FUNC_ARGS_PASSTHRU);
/* Register our cluster cache list item */
le_cluster_slot_cache = zend_register_list_destructors_ex(NULL, cluster_cache_dtor,
"Redis cluster slot cache",
module_number);
/* RedisException class */
redis_exception_ce = register_class_RedisException(spl_ce_RuntimeException);
#ifdef PHP_SESSION
php_session_register_module(&ps_mod_redis);
php_session_register_module(&ps_mod_redis_cluster);
#endif
/* Register resource destructors */
le_redis_pconnect = zend_register_list_destructors_ex(NULL, redis_connections_pool_dtor,
"phpredis persistent connections pool", module_number);
return SUCCESS;
}
static const char *
get_available_serializers(void)
{
#ifdef HAVE_REDIS_JSON
#ifdef HAVE_REDIS_IGBINARY
#ifdef HAVE_REDIS_MSGPACK
return "php, json, igbinary, msgpack";
#else
return "php, json, igbinary";
#endif
#else
#ifdef HAVE_REDIS_MSGPACK
return "php, json, msgpack";
#else
return "php, json";
#endif
#endif
#else
#ifdef HAVE_REDIS_IGBINARY
#ifdef HAVE_REDIS_MSGPACK
return "php, igbinary, msgpack";
#else
return "php, igbinary";
#endif
#else
#ifdef HAVE_REDIS_MSGPACK
return "php, msgpack";
#else
return "php";
#endif
#endif
#endif
}
/**
* PHP_MINFO_FUNCTION
*/
PHP_MINFO_FUNCTION(redis)
{
smart_str names = {0,};
php_info_print_table_start();
php_info_print_table_header(2, "Redis Support", "enabled");
php_info_print_table_row(2, "Redis Version", PHP_REDIS_VERSION);
php_info_print_table_row(2, "Redis Sentinel Version", PHP_REDIS_SENTINEL_VERSION);
#ifdef GIT_REVISION
php_info_print_table_row(2, "Git revision", "$Id: " GIT_REVISION " $");
#endif
php_info_print_table_row(2, "Available serializers", get_available_serializers());
#ifdef HAVE_REDIS_LZF
smart_str_appends(&names, "lzf");
#endif
#ifdef HAVE_REDIS_ZSTD
if (names.s) {
smart_str_appends(&names, ", ");
}
smart_str_appends(&names, "zstd");
#endif
#ifdef HAVE_REDIS_LZ4
if (names.s) {
smart_str_appends(&names, ", ");
}
smart_str_appends(&names, "lz4");
#endif
if (names.s) {
smart_str_0(&names);
php_info_print_table_row(2, "Available compression", ZSTR_VAL(names.s));
}
smart_str_free(&names);
php_info_print_table_end();
DISPLAY_INI_ENTRIES();
}
/* {{{ proto Redis Redis::__construct(array $options = null)
Public constructor */
PHP_METHOD(Redis, __construct)
{
HashTable *opts = NULL;
redis_object *redis;
ZEND_PARSE_PARAMETERS_START(0, 1)
Z_PARAM_OPTIONAL
Z_PARAM_ARRAY_HT_OR_NULL(opts)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_THROWS());
redis = PHPREDIS_ZVAL_GET_OBJECT(redis_object, getThis());
redis->sock = redis_sock_create(ZEND_STRL("127.0.0.1"), 6379, 0, 0, 0, NULL, 0);
if (opts != NULL && redis_sock_configure(redis->sock, opts) != SUCCESS) {
RETURN_THROWS();
}
}
/* }}} */
/* {{{ proto Redis Redis::__destruct()
Public Destructor
*/
PHP_METHOD(Redis,__destruct) {
if (zend_parse_parameters_none() == FAILURE) {
RETURN_FALSE;
}
// Grab our socket
RedisSock *redis_sock;
if ((redis_sock = redis_sock_get_instance(getThis(), 1)) == NULL) {
RETURN_FALSE;
}
// If we think we're in MULTI mode, send a discard
if (IS_MULTI(redis_sock)) {
if (!IS_PIPELINE(redis_sock) && redis_sock->stream) {
// Discard any multi commands, and free any callbacks that have been
// queued
redis_send_discard(redis_sock);
}
free_reply_callbacks(redis_sock);
}
}
/* {{{ proto boolean Redis::connect(string host, int port [, double timeout [, long retry_interval]])
*/
PHP_METHOD(Redis, connect)
{
if (redis_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0) == FAILURE) {
RETURN_FALSE;
} else {
RETURN_TRUE;
}
}
/* }}} */
/* {{{ proto boolean Redis::pconnect(string host, int port [, double timeout])
*/
PHP_METHOD(Redis, pconnect)
{
if (redis_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1) == FAILURE) {
RETURN_FALSE;
} else {
RETURN_TRUE;
}
}
/* }}} */
PHP_REDIS_API int
redis_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
{
zval *object, *context = NULL, *ele;
char *host = NULL, *persistent_id = NULL;
zend_long port = -1, retry_interval = 0;
size_t host_len, persistent_id_len;
double timeout = 0.0, read_timeout = 0.0;
redis_object *redis;
int af_unix;
#ifdef ZTS
/* not sure how in threaded mode this works so disabled persistence at
* first */
persistent = 0;
#endif
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
"Os|lds!lda", &object, redis_ce, &host,
&host_len, &port, &timeout, &persistent_id,
&persistent_id_len, &retry_interval,
&read_timeout, &context) == FAILURE)
{
return FAILURE;
}
/* Disregard persistent_id if we're not opening a persistent connection */
if (!persistent) {
persistent_id = NULL;
}
if (timeout > INT_MAX) {
REDIS_VALUE_EXCEPTION("Invalid connect timeout");
return FAILURE;
}
if (read_timeout > INT_MAX) {
REDIS_VALUE_EXCEPTION("Invalid read timeout");
return FAILURE;
}
if (retry_interval < 0L || retry_interval > INT_MAX) {
REDIS_VALUE_EXCEPTION("Invalid retry interval");
return FAILURE;
}
/* Does the host look like a unix socket */
af_unix = (host_len > 0 && host[0] == '/') ||
(host_len > 6 && !strncasecmp(host, "unix://", sizeof("unix://") - 1)) ||
(host_len > 6 && !strncasecmp(host, "file://", sizeof("file://") - 1));
/* If it's not a unix socket, set to default */
if (port == -1 && !af_unix) {
port = 6379;
}
redis = PHPREDIS_ZVAL_GET_OBJECT(redis_object, object);
/* if there is a redis sock already we have to remove it */
if (redis->sock) {
redis_sock_disconnect(redis->sock, 0, 1);
redis_free_socket(redis->sock);
}
redis->sock = redis_sock_create(host, host_len, port, timeout, read_timeout, persistent,
persistent_id, retry_interval);
if (context) {
/* Stream context (e.g. TLS) */
if ((ele = REDIS_HASH_STR_FIND_STATIC(Z_ARRVAL_P(context), "stream"))) {
redis_sock_set_stream_context(redis->sock, ele);
}
/* AUTH */
if ((ele = REDIS_HASH_STR_FIND_STATIC(Z_ARRVAL_P(context), "auth"))) {
redis_sock_set_auth_zval(redis->sock, ele);
}
}
if (redis_sock_connect(redis->sock) != SUCCESS) {
if (redis->sock->err) {
REDIS_THROW_EXCEPTION(ZSTR_VAL(redis->sock->err), 0);
}
redis_free_socket(redis->sock);
redis->sock = NULL;
return FAILURE;
}
return SUCCESS;
}
/* {{{ proto long Redis::bitop(string op, string key, ...) */
PHP_METHOD(Redis, bitop) {
REDIS_PROCESS_CMD(bitop, redis_long_response);
}
/* }}} */
/* {{{ proto long Redis::bitcount(string key, [int start], [int end])
*/
PHP_METHOD(Redis, bitcount)
{
REDIS_PROCESS_CMD(bitcount, redis_long_response);
}
/* }}} */
/* {{{ proto integer Redis::bitpos(string key, int bit, [int start, int end]) */
PHP_METHOD(Redis, bitpos)
{
REDIS_PROCESS_CMD(bitpos, redis_long_response);
}
/* }}} */
/* {{{ proto boolean Redis::close()
*/
PHP_METHOD(Redis, close)
{
RedisSock *redis_sock = redis_sock_get_connected(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (redis_sock_disconnect(redis_sock, 1, 1) == SUCCESS) {
RETURN_TRUE;
}
RETURN_FALSE;
}
/* }}} */
/* {{{ proto boolean Redis::set(string key, mixed val, long timeout,
* [array opt) */
PHP_METHOD(Redis, set) {
REDIS_PROCESS_CMD(set, redis_set_response);
}
/* {{{ proto boolean Redis::setex(string key, long expire, string value)
*/
PHP_METHOD(Redis, setex)
{
REDIS_PROCESS_KW_CMD("SETEX", redis_key_long_val_cmd, redis_boolean_response);
}
/* {{{ proto boolean Redis::psetex(string key, long expire, string value)
*/
PHP_METHOD(Redis, psetex)
{
REDIS_PROCESS_KW_CMD("PSETEX", redis_key_long_val_cmd, redis_boolean_response);
}
/* {{{ proto boolean Redis::setnx(string key, string value)
*/
PHP_METHOD(Redis, setnx)
{
REDIS_PROCESS_KW_CMD("SETNX", redis_kv_cmd, redis_1_response);
}
/* }}} */
/* {{{ proto string Redis::getSet(string key, string value)
*/
PHP_METHOD(Redis, getset)
{
REDIS_PROCESS_KW_CMD("GETSET", redis_kv_cmd, redis_string_response);
}
/* }}} */
/* {{{ proto string Redis::randomKey()
*/
PHP_METHOD(Redis, randomKey)
{
REDIS_PROCESS_KW_CMD("RANDOMKEY", redis_empty_cmd, redis_ping_response);
}
/* }}} */
/* {{{ proto string Redis::echo(string msg)
*/
PHP_METHOD(Redis, echo)
{
REDIS_PROCESS_KW_CMD("ECHO", redis_str_cmd, redis_string_response);
}
/* }}} */
/* {{{ proto string Redis::rename(string key_src, string key_dst)
*/
PHP_METHOD(Redis, rename)
{
REDIS_PROCESS_KW_CMD("RENAME", redis_key_key_cmd, redis_boolean_response);
}
/* }}} */
/* {{{ proto string Redis::renameNx(string key_src, string key_dst)
*/
PHP_METHOD(Redis, renameNx)
{
REDIS_PROCESS_KW_CMD("RENAMENX", redis_key_key_cmd, redis_1_response);
}
/* }}} */
/** {{{ proto bool Redis::reset()
*/
PHP_METHOD(Redis, reset)
{
char *response;
int response_len;
RedisSock *redis_sock;
smart_string cmd = {0};
zend_bool ret = 0;
if ((redis_sock = redis_sock_get(getThis(), 0)) == NULL) {
RETURN_FALSE;
}
if (IS_PIPELINE(redis_sock)) {
php_error_docref(NULL, E_ERROR, "Reset ins't allowed in pipeline mode!");
RETURN_FALSE;
}
redis_cmd_init_sstr(&cmd, 0, "RESET", 5);
REDIS_PROCESS_REQUEST(redis_sock, cmd.c, cmd.len);
if ((response = redis_sock_read(redis_sock, &response_len)) != NULL) {
ret = REDIS_STRCMP_STATIC(response, response_len, "+RESET");
efree(response);
}
if (!ret) {
if (IS_ATOMIC(redis_sock)) {
RETURN_FALSE;
}
REDIS_THROW_EXCEPTION("Reset failed in multi mode!", 0);
RETURN_ZVAL(getThis(), 1, 0);
}
free_reply_callbacks(redis_sock);
redis_sock->status = REDIS_SOCK_STATUS_CONNECTED;
redis_sock->mode = ATOMIC;
redis_sock->dbNumber = 0;
redis_sock->watching = 0;
RETURN_TRUE;
}
/* }}} */
/* {{{ proto string Redis::get(string key)
*/
PHP_METHOD(Redis, get)
{
REDIS_PROCESS_KW_CMD("GET", redis_key_cmd, redis_string_response);
}
/* }}} */
/* {{{ proto string Redis::getDel(string key)
*/
PHP_METHOD(Redis, getDel)
{
REDIS_PROCESS_KW_CMD("GETDEL", redis_key_cmd, redis_string_response);
}
/* }}} */
/* {{{ proto string Redis::getEx(string key [, array $options = []])
*/
PHP_METHOD(Redis, getEx)
{
REDIS_PROCESS_CMD(getex, redis_string_response);
}
/* }}} */
/* {{{ proto string Redis::ping()
*/
PHP_METHOD(Redis, ping)
{
REDIS_PROCESS_KW_CMD("PING", redis_opt_str_cmd, redis_read_variant_reply);
}
/* }}} */
/* {{{ proto boolean Redis::incr(string key [,int value])
*/
PHP_METHOD(Redis, incr){
REDIS_PROCESS_CMD(incr, redis_long_response);
}
/* }}} */
/* {{{ proto boolean Redis::incrBy(string key ,int value)
*/
PHP_METHOD(Redis, incrBy){
REDIS_PROCESS_KW_CMD("INCRBY", redis_key_long_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto float Redis::incrByFloat(string key, float value)
*/
PHP_METHOD(Redis, incrByFloat) {
REDIS_PROCESS_KW_CMD("INCRBYFLOAT", redis_key_dbl_cmd, redis_bulk_double_response);
}
/* }}} */
/* {{{ proto boolean Redis::decr(string key) */
PHP_METHOD(Redis, decr)
{
REDIS_PROCESS_CMD(decr, redis_long_response);
}
/* }}} */
/* {{{ proto boolean Redis::decrBy(string key ,int value)
*/
PHP_METHOD(Redis, decrBy){
REDIS_PROCESS_KW_CMD("DECRBY", redis_key_long_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto array Redis::mget(array keys)
*/
PHP_METHOD(Redis, mget) {
REDIS_PROCESS_CMD(mget, redis_sock_read_multibulk_reply);
}
/* {{{ proto boolean Redis::exists(string $key, string ...$more_keys)
*/
PHP_METHOD(Redis, exists) {
REDIS_PROCESS_KW_CMD("EXISTS", redis_varkey_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto boolean Redis::touch(string $key, string ...$more_keys)
*/
PHP_METHOD(Redis, touch) {
REDIS_PROCESS_KW_CMD("TOUCH", redis_varkey_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto boolean Redis::del(string key)
*/
PHP_METHOD(Redis, del) {
REDIS_PROCESS_KW_CMD("DEL", redis_varkey_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto long Redis::unlink(string $key1, string $key2 [, string $key3...]) }}}
* {{{ proto long Redis::unlink(array $keys) */
PHP_METHOD(Redis, unlink)
{
REDIS_PROCESS_KW_CMD("UNLINK", redis_varkey_cmd, redis_long_response);
}
PHP_REDIS_API void redis_set_watch(RedisSock *redis_sock)
{
redis_sock->watching = 1;
}
PHP_REDIS_API int redis_watch_response(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, zval *z_tab, void *ctx)
{
return redis_boolean_response_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock,
z_tab, ctx, redis_set_watch);
}
/* {{{ proto boolean Redis::watch(string key1, string key2...)
*/
PHP_METHOD(Redis, watch) {
REDIS_PROCESS_KW_CMD("WATCH", redis_varkey_cmd, redis_watch_response);
}
/* }}} */
PHP_REDIS_API void redis_clear_watch(RedisSock *redis_sock)
{
redis_sock->watching = 0;
}
PHP_REDIS_API int redis_unwatch_response(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, zval *z_tab,
void *ctx)
{
return redis_boolean_response_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock,
z_tab, ctx, redis_clear_watch);
}
/* {{{ proto boolean Redis::unwatch()
*/
PHP_METHOD(Redis, unwatch)
{
REDIS_PROCESS_KW_CMD("UNWATCH", redis_empty_cmd, redis_unwatch_response);
}
/* }}} */
/* {{{ proto array Redis::keys(string pattern)
*/
PHP_METHOD(Redis, keys)
{
REDIS_PROCESS_KW_CMD("KEYS", redis_key_cmd, redis_mbulk_reply_raw);
}
/* }}} */
/* {{{ proto int Redis::type(string key)
*/
PHP_METHOD(Redis, type)
{
REDIS_PROCESS_KW_CMD("TYPE", redis_key_cmd, redis_type_response);
}
/* }}} */
/* {{{ proto mixed Redis::acl(string $op, ...) }}} */
PHP_METHOD(Redis, acl) {
REDIS_PROCESS_CMD(acl, redis_acl_response);
}
/* {{{ proto long Redis::append(string key, string val) */
PHP_METHOD(Redis, append)
{
REDIS_PROCESS_KW_CMD("APPEND", redis_kv_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto string Redis::GetRange(string key, long start, long end) */
PHP_METHOD(Redis, getRange)
{
REDIS_PROCESS_KW_CMD("GETRANGE", redis_key_long_long_cmd,
redis_string_response);
}
/* }}} */
/* {{{ proto mixed Redis::lcs(string $key1, string $key2, ?array $options = NULL); */
PHP_METHOD(Redis, lcs) {
REDIS_PROCESS_CMD(lcs, redis_read_variant_reply);
}
/* }}} */
/* {{{ proto string Redis::setRange(string key, long start, string value) */
PHP_METHOD(Redis, setRange)
{
REDIS_PROCESS_KW_CMD("SETRANGE", redis_key_long_str_cmd,
redis_long_response);
}
/* }}} */
/* {{{ proto long Redis::getbit(string key, long idx) */
PHP_METHOD(Redis, getBit)
{
REDIS_PROCESS_KW_CMD("GETBIT", redis_key_long_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto long Redis::setbit(string key, long idx, bool|int value) */
PHP_METHOD(Redis, setBit)
{
REDIS_PROCESS_CMD(setbit, redis_long_response);
}
/* }}} */
/* {{{ proto long Redis::strlen(string key) */
PHP_METHOD(Redis, strlen)
{
REDIS_PROCESS_KW_CMD("STRLEN", redis_key_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto boolean Redis::lPush(string key , string value)
*/
PHP_METHOD(Redis, lPush)
{
REDIS_PROCESS_KW_CMD("LPUSH", redis_key_varval_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto boolean Redis::rPush(string key , string value)
*/
PHP_METHOD(Redis, rPush)
{
REDIS_PROCESS_KW_CMD("RPUSH", redis_key_varval_cmd, redis_long_response);
}
/* }}} */
PHP_METHOD(Redis, lInsert)
{
REDIS_PROCESS_CMD(linsert, redis_long_response);
}
/* {{{ proto long Redis::lPushx(string key, mixed value) */
PHP_METHOD(Redis, lPushx)
{
REDIS_PROCESS_KW_CMD("LPUSHX", redis_kv_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto long Redis::rPushx(string key, mixed value) */
PHP_METHOD(Redis, rPushx)
{
REDIS_PROCESS_KW_CMD("RPUSHX", redis_kv_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto string Redis::lPop(string key, [int count = 0]) */
PHP_METHOD(Redis, lPop)
{
REDIS_PROCESS_KW_CMD("LPOP", redis_pop_cmd, redis_pop_response);
}
/* }}} */
/* {{{ proto string Redis::lPos(string key, mixed value, [array options = null]) */
PHP_METHOD(Redis, lPos)
{
REDIS_PROCESS_CMD(lpos, redis_lpos_response);
}
/* }}} */
/* {{{ proto string Redis::rPop(string key, [int count = 0]) */
PHP_METHOD(Redis, rPop)
{
REDIS_PROCESS_KW_CMD("RPOP", redis_pop_cmd, redis_pop_response);
}
/* }}} */
/* {{{ proto string Redis::blPop(string key1, string key2, ..., int timeout) */
PHP_METHOD(Redis, blPop)
{
REDIS_PROCESS_KW_CMD("BLPOP", redis_blocking_pop_cmd, redis_sock_read_multibulk_reply);
}
/* }}} */
/* {{{ proto string Redis::brPop(string key1, string key2, ..., int timeout) */
PHP_METHOD(Redis, brPop)
{
REDIS_PROCESS_KW_CMD("BRPOP", redis_blocking_pop_cmd, redis_sock_read_multibulk_reply);
}
/* }}} */
/* {{{ proto int Redis::lLen(string key) */
PHP_METHOD(Redis, lLen)
{
REDIS_PROCESS_KW_CMD("LLEN", redis_key_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto string Redis::blMove(string source, string destination, string wherefrom, string whereto, double $timeout) */
PHP_METHOD(Redis, blmove) {
REDIS_PROCESS_KW_CMD("BLMOVE", redis_lmove_cmd, redis_string_response);
}
/* {{{ proto string Redis::lMove(string source, string destination, string wherefrom, string whereto) */
PHP_METHOD(Redis, lMove) {
REDIS_PROCESS_KW_CMD("LMOVE", redis_lmove_cmd, redis_string_response);
}
/* {{{ proto boolean Redis::lrem(string list, string value, int count = 0) */
PHP_METHOD(Redis, lrem)
{
REDIS_PROCESS_CMD(lrem, redis_long_response);
}
/* }}} */
/* {{{ proto boolean Redis::ltrim(string key , int start , int end) */
PHP_METHOD(Redis, ltrim)
{
REDIS_PROCESS_KW_CMD("LTRIM", redis_key_long_long_cmd,
redis_boolean_response);
}
/* }}} */
/* {{{ proto string Redis::lindex(string key , int index) */
PHP_METHOD(Redis, lindex)
{
REDIS_PROCESS_KW_CMD("LINDEX", redis_key_long_cmd, redis_string_response);
}
/* }}} */
/* {{{ proto array Redis::lrange(string key, int start , int end) */
PHP_METHOD(Redis, lrange)
{
REDIS_PROCESS_KW_CMD("LRANGE", redis_key_long_long_cmd,
redis_sock_read_multibulk_reply);
}
/* }}} */
/* {{{ proto long Redis::sAdd(string key , mixed value) */
PHP_METHOD(Redis, sAdd)
{
REDIS_PROCESS_KW_CMD("SADD", redis_key_varval_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto boolean Redis::sAddArray(string key, array $values) */
PHP_METHOD(Redis, sAddArray) {
REDIS_PROCESS_KW_CMD("SADD", redis_key_val_arr_cmd, redis_long_response);
} /* }}} */
/* {{{ proto int Redis::scard(string key) */
PHP_METHOD(Redis, scard)
{
REDIS_PROCESS_KW_CMD("SCARD", redis_key_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto boolean Redis::srem(string set, string value) */
PHP_METHOD(Redis, srem)
{
REDIS_PROCESS_KW_CMD("SREM", redis_key_varval_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto boolean Redis::sMove(string src, string dst, mixed value) */
PHP_METHOD(Redis, sMove)
{
REDIS_PROCESS_CMD(smove, redis_1_response);
}
/* }}} */
/* {{{ proto string Redis::sPop(string key) */
PHP_METHOD(Redis, sPop)
{
if (ZEND_NUM_ARGS() == 1) {
REDIS_PROCESS_KW_CMD("SPOP", redis_key_cmd, redis_string_response);
} else if (ZEND_NUM_ARGS() == 2) {
REDIS_PROCESS_KW_CMD("SPOP", redis_key_long_cmd, redis_sock_read_multibulk_reply);
} else {
ZEND_WRONG_PARAM_COUNT();
}
}
/* }}} */
/* {{{ proto string Redis::sRandMember(string key [int count]) */
PHP_METHOD(Redis, sRandMember)
{
REDIS_PROCESS_CMD(srandmember, redis_srandmember_response);
}
/* }}} */
/* {{{ proto boolean Redis::sismember(string set, string value) */
PHP_METHOD(Redis, sismember)
{
REDIS_PROCESS_KW_CMD("SISMEMBER", redis_kv_cmd, redis_1_response);
}
/* }}} */
/* {{{ proto array Redis::sMembers(string set) */
PHP_METHOD(Redis, sMembers)
{
REDIS_PROCESS_KW_CMD("SMEMBERS", redis_key_cmd,
redis_sock_read_multibulk_reply);
}
/* {{{ proto array Redis::sMisMember(string key, string member0, ...memberN) */
PHP_METHOD(Redis, sMisMember)
{
REDIS_PROCESS_KW_CMD("SMISMEMBER", redis_key_varval_cmd, redis_read_variant_reply);
}
/* }}} */
/* {{{ proto array Redis::sInter(string key0, ... string keyN) */
PHP_METHOD(Redis, sInter) {
REDIS_PROCESS_KW_CMD("SINTER", redis_varkey_cmd, redis_sock_read_multibulk_reply);
}
/* }}} */
PHP_METHOD(Redis, sintercard) {
REDIS_PROCESS_KW_CMD("SINTERCARD", redis_intercard_cmd, redis_long_response);
}
/* {{{ proto array Redis::sInterStore(string dst, string key0,...string keyN) */
PHP_METHOD(Redis, sInterStore) {
REDIS_PROCESS_KW_CMD("SINTERSTORE", redis_varkey_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto array Redis::sUnion(string key0, ... string keyN) */
PHP_METHOD(Redis, sUnion) {
REDIS_PROCESS_KW_CMD("SUNION", redis_varkey_cmd, redis_sock_read_multibulk_reply);
}
/* }}} */
/* {{{ proto array Redis::sUnionStore(array|string $key, string ...$srckeys) */
PHP_METHOD(Redis, sUnionStore) {
REDIS_PROCESS_KW_CMD("SUNIONSTORE", redis_varkey_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto array Redis::sDiff(string key0, ... string keyN) */
PHP_METHOD(Redis, sDiff) {
REDIS_PROCESS_KW_CMD("SDIFF", redis_varkey_cmd, redis_sock_read_multibulk_reply);
}
/* }}} */
/* {{{ proto array Redis::sDiffStore(string dst, string key0, ... keyN) */
PHP_METHOD(Redis, sDiffStore) {
REDIS_PROCESS_KW_CMD("SDIFFSTORE", redis_varkey_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto array Redis::sort(string key, array options) */
PHP_METHOD(Redis, sort) {
REDIS_PROCESS_KW_CMD("SORT", redis_sort_cmd, redis_read_variant_reply);
}
/* {{{ proto array Redis::sort(string key, array options) */
PHP_METHOD(Redis, sort_ro) {
REDIS_PROCESS_KW_CMD("SORT_RO", redis_sort_cmd, redis_read_variant_reply);
}
static void
generic_sort_cmd(INTERNAL_FUNCTION_PARAMETERS, int desc, int alpha)
{
zval *object, *zele, *zget = NULL;
RedisSock *redis_sock;
zend_string *zpattern;
char *key = NULL, *pattern = NULL, *store = NULL;
size_t keylen, patternlen, storelen;
zend_long offset = -1, count = -1;
int argc = 1; /* SORT key is the simplest SORT command */
smart_string cmd = {0};
/* Parse myriad of sort arguments */
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
"Os|s!z!lls", &object, redis_ce, &key,
&keylen, &pattern, &patternlen, &zget,
&offset, &count, &store, &storelen)
== FAILURE)
{
RETURN_FALSE;
}
/* Ensure we're sorting something, and we can get context */
if (keylen == 0 || !(redis_sock = redis_sock_get(object, 0)))
RETURN_FALSE;
/* Start calculating argc depending on input arguments */
if (pattern && patternlen) argc += 2; /* BY pattern */
if (offset >= 0 && count >= 0) argc += 3; /* LIMIT offset count */
if (alpha) argc += 1; /* ALPHA */
if (store) argc += 2; /* STORE destination */
if (desc) argc += 1; /* DESC (ASC is the default) */
/* GET is special. It can be 0 .. N arguments depending what we have */
if (zget) {
if (Z_TYPE_P(zget) == IS_ARRAY)
argc += zend_hash_num_elements(Z_ARRVAL_P(zget));
else if (Z_STRLEN_P(zget) > 0) {
argc += 2; /* GET pattern */
}
}
/* Start constructing final command and append key */
redis_cmd_init_sstr(&cmd, argc, "SORT", 4);
redis_cmd_append_sstr_key(&cmd, key, keylen, redis_sock, NULL);
/* BY pattern */
if (pattern && patternlen) {
redis_cmd_append_sstr(&cmd, "BY", sizeof("BY") - 1);
redis_cmd_append_sstr(&cmd, pattern, patternlen);
}
/* LIMIT offset count */
if (offset >= 0 && count >= 0) {
redis_cmd_append_sstr(&cmd, "LIMIT", sizeof("LIMIT") - 1);
redis_cmd_append_sstr_long(&cmd, offset);
redis_cmd_append_sstr_long(&cmd, count);
}
/* Handle any number of GET pattern arguments we've been passed */
if (zget != NULL) {
if (Z_TYPE_P(zget) == IS_ARRAY) {
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zget), zele) {
zpattern = zval_get_string(zele);
redis_cmd_append_sstr(&cmd, "GET", sizeof("GET") - 1);
redis_cmd_append_sstr(&cmd, ZSTR_VAL(zpattern), ZSTR_LEN(zpattern));
zend_string_release(zpattern);
} ZEND_HASH_FOREACH_END();
} else {
zpattern = zval_get_string(zget);
redis_cmd_append_sstr(&cmd, "GET", sizeof("GET") - 1);
redis_cmd_append_sstr(&cmd, ZSTR_VAL(zpattern), ZSTR_LEN(zpattern));
zend_string_release(zpattern);
}
}
/* Append optional DESC and ALPHA modifiers */
if (desc) redis_cmd_append_sstr(&cmd, "DESC", sizeof("DESC") - 1);
if (alpha) redis_cmd_append_sstr(&cmd, "ALPHA", sizeof("ALPHA") - 1);
/* Finally append STORE if we've got it */
if (store && storelen) {
redis_cmd_append_sstr(&cmd, "STORE", sizeof("STORE") - 1);
redis_cmd_append_sstr_key(&cmd, store, storelen, redis_sock, NULL);
}
REDIS_PROCESS_REQUEST(redis_sock, cmd.c, cmd.len);
if (IS_ATOMIC(redis_sock)) {
if (redis_read_variant_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU,
redis_sock, NULL, NULL) < 0)
{
RETURN_FALSE;
}
}
REDIS_PROCESS_RESPONSE(redis_read_variant_reply);
}
/* {{{ proto array Redis::sortAsc(string key, string pattern, string get,
* int start, int end, bool getList]) */
PHP_METHOD(Redis, sortAsc)
{
generic_sort_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0);
}
/* }}} */
/* {{{ proto array Redis::sortAscAlpha(string key, string pattern, string get,
* int start, int end, bool getList]) */
PHP_METHOD(Redis, sortAscAlpha)
{
generic_sort_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 1);
}
/* }}} */
/* {{{ proto array Redis::sortDesc(string key, string pattern, string get,
* int start, int end, bool getList]) */
PHP_METHOD(Redis, sortDesc)
{
generic_sort_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 0);
}
/* }}} */
/* {{{ proto array Redis::sortDescAlpha(string key, string pattern, string get,
* int start, int end, bool getList]) */
PHP_METHOD(Redis, sortDescAlpha)
{
generic_sort_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 1);
}
/* }}} */
/* {{{ proto array Redis::expire(string key, int timeout) */
PHP_METHOD(Redis, expire) {
REDIS_PROCESS_KW_CMD("EXPIRE", redis_expire_cmd, redis_1_response);
}
/* }}} */
/* {{{ proto bool Redis::pexpire(string key, long ms) */
PHP_METHOD(Redis, pexpire) {
REDIS_PROCESS_KW_CMD("PEXPIRE", redis_expire_cmd, redis_1_response);
}
/* }}} */
/* {{{ proto array Redis::expireAt(string key, int timestamp) */
PHP_METHOD(Redis, expireAt) {
REDIS_PROCESS_KW_CMD("EXPIREAT", redis_expire_cmd, redis_1_response);
}
/* }}} */
/* {{{ proto array Redis::pexpireAt(string key, int timestamp) */
PHP_METHOD(Redis, pexpireAt) {
REDIS_PROCESS_KW_CMD("PEXPIREAT", redis_expire_cmd, redis_1_response);
}
/* }}} */
/* {{{ proto Redis::expiretime(string $key): int */
PHP_METHOD(Redis, expiretime) {
REDIS_PROCESS_KW_CMD("EXPIRETIME", redis_key_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto Redis::expiretime(string $key): int */
PHP_METHOD(Redis, pexpiretime) {
REDIS_PROCESS_KW_CMD("PEXPIRETIME", redis_key_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto array Redis::lSet(string key, int index, string value) */
PHP_METHOD(Redis, lSet) {
REDIS_PROCESS_KW_CMD("LSET", redis_key_long_val_cmd,
redis_boolean_response);
}
/* }}} */
/* {{{ proto string Redis::save() */
PHP_METHOD(Redis, save)
{
REDIS_PROCESS_KW_CMD("SAVE", redis_empty_cmd, redis_boolean_response);
}
/* }}} */
/* {{{ proto string Redis::bgSave() */
PHP_METHOD(Redis, bgSave)
{
REDIS_PROCESS_KW_CMD("BGSAVE", redis_empty_cmd, redis_boolean_response);
}
/* }}} */
/* {{{ proto integer Redis::lastSave() */
PHP_METHOD(Redis, lastSave)
{
REDIS_PROCESS_KW_CMD("LASTSAVE", redis_empty_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto bool Redis::failover([array to [,bool abort [,int timeout]]] ) */
PHP_METHOD(Redis, failover)
{
REDIS_PROCESS_CMD(failover, redis_boolean_response);
}
/* }}} */
/* {{{ proto bool Redis::flushDB([bool async]) */
PHP_METHOD(Redis, flushDB)
{
REDIS_PROCESS_KW_CMD("FLUSHDB", redis_flush_cmd, redis_boolean_response);
}
/* }}} */
/* {{{ proto bool Redis::flushAll([bool async]) */
PHP_METHOD(Redis, flushAll)
{
REDIS_PROCESS_KW_CMD("FLUSHALL", redis_flush_cmd, redis_boolean_response);
}
/* }}} */
/* {{{ proto mixed Redis::function(string op, mixed ...args) */
PHP_METHOD(Redis, function)
{
REDIS_PROCESS_CMD(function, redis_function_response)
}
/* {{{ proto int Redis::dbSize() */
PHP_METHOD(Redis, dbSize)
{
REDIS_PROCESS_KW_CMD("DBSIZE", redis_empty_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto bool Redis::auth(string passwd) */
PHP_METHOD(Redis, auth) {
REDIS_PROCESS_CMD(auth, redis_boolean_response);
}
/* }}} */
/* {{{ proto long Redis::persist(string key) */
PHP_METHOD(Redis, persist) {
REDIS_PROCESS_KW_CMD("PERSIST", redis_key_cmd, redis_1_response);
}
/* }}} */
/* {{{ proto long Redis::ttl(string key) */
PHP_METHOD(Redis, ttl) {
REDIS_PROCESS_KW_CMD("TTL", redis_key_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto long Redis::pttl(string key) */
PHP_METHOD(Redis, pttl) {
REDIS_PROCESS_KW_CMD("PTTL", redis_key_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto array Redis::info() */
PHP_METHOD(Redis, info) {
REDIS_PROCESS_CMD(info, redis_info_response);
}
/* }}} */
/* {{{ proto bool Redis::select(long dbNumber) */
PHP_METHOD(Redis, select) {
REDIS_PROCESS_CMD(select, redis_select_response);
}
/* }}} */
/* {{{ proto bool Redis::swapdb(long srcdb, long dstdb) */
PHP_METHOD(Redis, swapdb) {
REDIS_PROCESS_KW_CMD("SWAPDB", redis_long_long_cmd, redis_boolean_response);
}
/* {{{ proto bool Redis::move(string key, long dbindex) */
PHP_METHOD(Redis, move) {
REDIS_PROCESS_KW_CMD("MOVE", redis_key_long_cmd, redis_1_response);
}
/* }}} */
/* {{{ proto bool Redis::mset(array (key => value, ...)) */
PHP_METHOD(Redis, mset) {
REDIS_PROCESS_KW_CMD("MSET", redis_mset_cmd, redis_boolean_response);
}
/* }}} */
/* {{{ proto bool Redis::msetnx(array (key => value, ...)) */
PHP_METHOD(Redis, msetnx) {
REDIS_PROCESS_KW_CMD("MSETNX", redis_mset_cmd, redis_1_response);
}
/* }}} */
/* {{{ proto string Redis::rpoplpush(string srckey, string dstkey) */
PHP_METHOD(Redis, rpoplpush)
{
REDIS_PROCESS_KW_CMD("RPOPLPUSH", redis_key_key_cmd, redis_string_response);
}
/* }}} */
/* {{{ proto string Redis::brpoplpush(string src, string dst, int timeout) */
PHP_METHOD(Redis, brpoplpush) {
REDIS_PROCESS_CMD(brpoplpush, redis_string_response);
}
/* }}} */
/* {{{ proto long Redis::zAdd(string key, int score, string value) */
PHP_METHOD(Redis, zAdd) {
REDIS_PROCESS_CMD(zadd, redis_zadd_response);
}
/* }}} */
/* {{{ proto array Redis::zRandMember(string key, array options) */
PHP_METHOD(Redis, zRandMember) {
REDIS_PROCESS_CMD(zrandmember, redis_zrandmember_response);
}
/* }}} */
/* {{{ proto array Redis::zRange(string key,int start,int end,bool scores = 0) */
PHP_METHOD(Redis, zRange) {
REDIS_PROCESS_KW_CMD("ZRANGE", redis_zrange_cmd, redis_zrange_response);
}
/* }}} */
PHP_METHOD(Redis, zrangestore) {
REDIS_PROCESS_KW_CMD("ZRANGESTORE", redis_zrange_cmd, redis_long_response);
}
/* {{{ proto array Redis::zRevRange(string k, long s, long e, bool scores = 0) */
PHP_METHOD(Redis, zRevRange) {
REDIS_PROCESS_KW_CMD("ZREVRANGE", redis_zrange_cmd, redis_zrange_response);
}
/* }}} */
/* {{{ proto array Redis::zRangeByScore(string k,string s,string e,array opt) */
PHP_METHOD(Redis, zRangeByScore) {
REDIS_PROCESS_KW_CMD("ZRANGEBYSCORE", redis_zrange_cmd, redis_zrange_response);
}
/* }}} */
/* {{{ proto array Redis::zRevRangeByScore(string key, string start, string end,
* array options) */
PHP_METHOD(Redis, zRevRangeByScore) {
REDIS_PROCESS_KW_CMD("ZREVRANGEBYSCORE", redis_zrange_cmd, redis_zrange_response);
}
/* }}} */
/* {{{ proto array Redis::zRangeByLex(string key, string min, string max, [
* offset, limit]) */
PHP_METHOD(Redis, zRangeByLex) {
REDIS_PROCESS_KW_CMD("ZRANGEBYLEX", redis_zrangebylex_cmd,
redis_sock_read_multibulk_reply);
}
/* }}} */
PHP_METHOD(Redis, zRevRangeByLex) {
REDIS_PROCESS_KW_CMD("ZREVRANGEBYLEX", redis_zrangebylex_cmd,
redis_sock_read_multibulk_reply);
}
/* }}} */
/* {{{ proto long Redis::zLexCount(string key, string min, string max) */
PHP_METHOD(Redis, zLexCount) {
REDIS_PROCESS_KW_CMD("ZLEXCOUNT", redis_gen_zlex_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto long Redis::zRemRangeByLex(string key, string min, string max) */
PHP_METHOD(Redis, zRemRangeByLex) {
REDIS_PROCESS_KW_CMD("ZREMRANGEBYLEX", redis_gen_zlex_cmd,
redis_long_response);
}
/* }}} */
/* {{{ proto long Redis::zRem(string key, string member) */
PHP_METHOD(Redis, zRem)
{
REDIS_PROCESS_KW_CMD("ZREM", redis_key_varval_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto long Redis::zRemRangeByScore(string k, string s, string e) */
PHP_METHOD(Redis, zRemRangeByScore)
{
REDIS_PROCESS_KW_CMD("ZREMRANGEBYSCORE", redis_key_str_str_cmd,
redis_long_response);
}
/* }}} */
/* {{{ proto long Redis::zRemRangeByRank(string key, long start, long end) */
PHP_METHOD(Redis, zRemRangeByRank)
{
REDIS_PROCESS_KW_CMD("ZREMRANGEBYRANK", redis_key_long_long_cmd,
redis_long_response);
}
/* }}} */
/* {{{ proto array Redis::zCount(string key, string start , string end) */
PHP_METHOD(Redis, zCount)
{
REDIS_PROCESS_KW_CMD("ZCOUNT", redis_key_str_str_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto long Redis::zCard(string key) */
PHP_METHOD(Redis, zCard)
{
REDIS_PROCESS_KW_CMD("ZCARD", redis_key_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto double Redis::zScore(string key, mixed member) */
PHP_METHOD(Redis, zScore)
{
REDIS_PROCESS_KW_CMD("ZSCORE", redis_kv_cmd,
redis_bulk_double_response);
}
/* }}} */
/* {{{ proto array Redis::zMscore(string key, string member0, ...memberN) */
PHP_METHOD(Redis, zMscore)
{
REDIS_PROCESS_KW_CMD("ZMSCORE", redis_key_varval_cmd, redis_mbulk_reply_double);
}
/* }}} */
/* {{{ proto long Redis::zRank(string key, string member) */
PHP_METHOD(Redis, zRank) {
REDIS_PROCESS_KW_CMD("ZRANK", redis_kv_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto long Redis::zRevRank(string key, string member) */
PHP_METHOD(Redis, zRevRank) {
REDIS_PROCESS_KW_CMD("ZREVRANK", redis_kv_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto double Redis::zIncrBy(string key, double value, mixed member) */
PHP_METHOD(Redis, zIncrBy)
{
REDIS_PROCESS_CMD(zincrby, redis_bulk_double_response);
}
/* }}} */
/* {{{ proto array Redis::zdiff(array keys, array options) */
PHP_METHOD(Redis, zdiff) {
REDIS_PROCESS_CMD(zdiff, redis_zdiff_response);
}
/* }}} */
/* {{{ proto array Redis::zinter(array keys, array|null weights, array options) */
PHP_METHOD(Redis, zinter) {
REDIS_PROCESS_KW_CMD("ZINTER", redis_zinterunion_cmd, redis_zdiff_response);
}
/* }}} */
PHP_METHOD(Redis, zintercard) {
REDIS_PROCESS_KW_CMD("ZINTERCARD", redis_intercard_cmd, redis_long_response);
}
/* {{{ proto array Redis::zunion(array keys, array|null weights, array options) */
PHP_METHOD(Redis, zunion) {
REDIS_PROCESS_KW_CMD("ZUNION", redis_zinterunion_cmd, redis_zdiff_response);
}
/* }}} */
/* {{{ proto array Redis::zdiffstore(string destination, array keys) */
PHP_METHOD(Redis, zdiffstore) {
REDIS_PROCESS_CMD(zdiffstore, redis_long_response);
}
/* }}} */
/* zinterstore */
PHP_METHOD(Redis, zinterstore) {
REDIS_PROCESS_KW_CMD("ZINTERSTORE", redis_zinterunionstore_cmd, redis_long_response);
}
/* zunionstore */
PHP_METHOD(Redis, zunionstore) {
REDIS_PROCESS_KW_CMD("ZUNIONSTORE", redis_zinterunionstore_cmd, redis_long_response);
}
/* {{{ proto array Redis::zPopMax(string key) */
PHP_METHOD(Redis, zPopMax)
{
if (ZEND_NUM_ARGS() == 1) {
REDIS_PROCESS_KW_CMD("ZPOPMAX", redis_key_cmd, redis_mbulk_reply_zipped_keys_dbl);
} else if (ZEND_NUM_ARGS() == 2) {
REDIS_PROCESS_KW_CMD("ZPOPMAX", redis_key_long_cmd, redis_mbulk_reply_zipped_keys_dbl);
} else {
ZEND_WRONG_PARAM_COUNT();
}
}
/* }}} */
/* {{{ proto array Redis::zPopMin(string key) */
PHP_METHOD(Redis, zPopMin)
{
if (ZEND_NUM_ARGS() == 1) {
REDIS_PROCESS_KW_CMD("ZPOPMIN", redis_key_cmd, redis_mbulk_reply_zipped_keys_dbl);
} else if (ZEND_NUM_ARGS() == 2) {
REDIS_PROCESS_KW_CMD("ZPOPMIN", redis_key_long_cmd, redis_mbulk_reply_zipped_keys_dbl);
} else {
ZEND_WRONG_PARAM_COUNT();
}
}
/* }}} */
/* {{{ proto Redis::bzPopMax(Array(keys) [, timeout]): Array */
PHP_METHOD(Redis, bzPopMax) {
REDIS_PROCESS_KW_CMD("BZPOPMAX", redis_blocking_pop_cmd, redis_sock_read_multibulk_reply);
}
/* }}} */
/* {{{ proto Redis::bzPopMin(Array(keys) [, timeout]): Array */
PHP_METHOD(Redis, bzPopMin) {
REDIS_PROCESS_KW_CMD("BZPOPMIN", redis_blocking_pop_cmd, redis_sock_read_multibulk_reply);
}
/* }}} */
/* {{{ proto Redis|array|false Redis::lmpop(array $keys, string $from, int $count = 1) */
PHP_METHOD(Redis, lmpop) {
REDIS_PROCESS_KW_CMD("LMPOP", redis_mpop_cmd, redis_mpop_response);
}
/* }}} */
/* {{{ proto Redis|array|false Redis::blmpop(double $timeout, array $keys, string $from, int $count = 1) */
PHP_METHOD(Redis, blmpop) {
REDIS_PROCESS_KW_CMD("BLMPOP", redis_mpop_cmd, redis_mpop_response);
}
/* }}} */
/* {{{ proto Redis|array|false Redis::zmpop(array $keys, string $from, int $count = 1) */
PHP_METHOD(Redis, zmpop) {
REDIS_PROCESS_KW_CMD("ZMPOP", redis_mpop_cmd, redis_mpop_response);
}
/* {{{ proto Redis|array|false Redis::bzmpop(double $timeout, array $keys, string $from, int $count = 1) */
PHP_METHOD(Redis, bzmpop) {
REDIS_PROCESS_KW_CMD("BZMPOP", redis_mpop_cmd, redis_mpop_response);
}
/* }}} */
/* hashes */
/* {{{ proto long Redis::hset(string key, string mem, string val) */
PHP_METHOD(Redis, hSet)
{
REDIS_PROCESS_CMD(hset, redis_long_response);
}
/* }}} */
/* {{{ proto bool Redis::hSetNx(string key, string mem, string val) */
PHP_METHOD(Redis, hSetNx)
{
REDIS_PROCESS_CMD(hsetnx, redis_1_response);
}
/* }}} */
/* {{{ proto string Redis::hget(string key, string mem) */
PHP_METHOD(Redis, hGet)
{
REDIS_PROCESS_KW_CMD("HGET", redis_key_str_cmd, redis_string_response);
}
/* }}} */
/* {{{ proto long Redis::hLen(string key) */
PHP_METHOD(Redis, hLen)
{
REDIS_PROCESS_KW_CMD("HLEN", redis_key_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto long Redis::hDel(string key, string mem1, ... memN) */
PHP_METHOD(Redis, hDel)
{
REDIS_PROCESS_CMD(hdel, redis_long_response);
}
/* }}} */
/* {{{ proto bool Redis::hExists(string key, string mem) */
PHP_METHOD(Redis, hExists)
{
REDIS_PROCESS_KW_CMD("HEXISTS", redis_key_str_cmd, redis_1_response);
}
/* {{{ proto array Redis::hkeys(string key) */
PHP_METHOD(Redis, hKeys)
{
REDIS_PROCESS_KW_CMD("HKEYS", redis_key_cmd, redis_mbulk_reply_raw);
}
/* }}} */
/* {{{ proto array Redis::hvals(string key) */
PHP_METHOD(Redis, hVals)
{
REDIS_PROCESS_KW_CMD("HVALS", redis_key_cmd,
redis_sock_read_multibulk_reply);
}
/* {{{ proto array Redis::hgetall(string key) */
PHP_METHOD(Redis, hGetAll) {
REDIS_PROCESS_KW_CMD("HGETALL", redis_key_cmd, redis_mbulk_reply_zipped_vals);
}
/* }}} */
/* {{{ proto double Redis::hIncrByFloat(string k, string me, double v) */
PHP_METHOD(Redis, hIncrByFloat)
{
REDIS_PROCESS_CMD(hincrbyfloat, redis_bulk_double_response);
}
/* }}} */
/* {{{ proto long Redis::hincrby(string key, string mem, long byval) */
PHP_METHOD(Redis, hIncrBy)
{
REDIS_PROCESS_CMD(hincrby, redis_long_response);
}
/* }}} */
/* {{{ array Redis::hMget(string hash, array keys) */
PHP_METHOD(Redis, hMget) {
REDIS_PROCESS_CMD(hmget, redis_mbulk_reply_assoc);
}
/* }}} */
/* {{{ proto bool Redis::hmset(string key, array keyvals) */
PHP_METHOD(Redis, hMset)
{
REDIS_PROCESS_CMD(hmset, redis_boolean_response);
}
/* }}} */
/* {{{ proto bool Redis::hRandField(string key, [array $options]) */
PHP_METHOD(Redis, hRandField)
{
REDIS_PROCESS_CMD(hrandfield, redis_hrandfield_response);
}
/* }}} */
/* {{{ proto long Redis::hstrlen(string key, string field) */
PHP_METHOD(Redis, hStrLen) {
REDIS_PROCESS_CMD(hstrlen, redis_long_response);
}
/* }}} */
/* flag : get, set {ATOMIC, MULTI, PIPELINE} */
PHP_METHOD(Redis, multi)
{
RedisSock *redis_sock;
char *resp;
int resp_len;
zval *object;
zend_long multi_value = MULTI;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
"O|l", &object, redis_ce, &multi_value)
== FAILURE)
{
RETURN_FALSE;
}
/* if the flag is activated, send the command, the reply will be "QUEUED"
* or -ERR */
if ((redis_sock = redis_sock_get(object, 0)) == NULL) {
RETURN_FALSE;
}
if (multi_value == PIPELINE) {
/* Cannot enter pipeline mode in a MULTI block */
if (IS_MULTI(redis_sock)) {
php_error_docref(NULL, E_ERROR, "Can't activate pipeline in multi mode!");
RETURN_FALSE;
}
/* Enable PIPELINE if we're not already in one */
if (IS_ATOMIC(redis_sock)) {
REDIS_ENABLE_MODE(redis_sock, PIPELINE);
}
} else if (multi_value == MULTI) {
/* Don't want to do anything if we're already in MULTI mode */
if (!IS_MULTI(redis_sock)) {
if (IS_PIPELINE(redis_sock)) {
PIPELINE_ENQUEUE_COMMAND(RESP_MULTI_CMD, sizeof(RESP_MULTI_CMD) - 1);
REDIS_SAVE_CALLBACK(NULL, NULL);
REDIS_ENABLE_MODE(redis_sock, MULTI);
} else {
SOCKET_WRITE_COMMAND(redis_sock, RESP_MULTI_CMD, sizeof(RESP_MULTI_CMD) - 1)
if ((resp = redis_sock_read(redis_sock, &resp_len)) == NULL) {
RETURN_FALSE;
} else if (strncmp(resp, "+OK", 3) != 0) {
efree(resp);
RETURN_FALSE;
}
efree(resp);
REDIS_ENABLE_MODE(redis_sock, MULTI);
}
}
} else {
php_error_docref(NULL, E_WARNING, "Unknown mode sent to Redis::multi");
RETURN_FALSE;
}
RETURN_ZVAL(getThis(), 1, 0);
}
/* discard */
PHP_METHOD(Redis, discard)
{
int ret = FAILURE;
RedisSock *redis_sock;
zval *object;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
&object, redis_ce) == FAILURE) {
RETURN_FALSE;
}
if ((redis_sock = redis_sock_get(object, 0)) == NULL) {
RETURN_FALSE;
}
if (IS_PIPELINE(redis_sock)) {
ret = SUCCESS;
if (redis_sock->pipeline_cmd) {
zend_string_release(redis_sock->pipeline_cmd);
redis_sock->pipeline_cmd = NULL;
}
} else if (IS_MULTI(redis_sock)) {
ret = redis_send_discard(redis_sock);
}
if (ret == SUCCESS) {
free_reply_callbacks(redis_sock);
redis_sock->mode = ATOMIC;
RETURN_TRUE;
}
RETURN_FALSE;
}
PHP_REDIS_API int
redis_sock_read_multibulk_multi_reply(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, zval *z_tab)
{
char inbuf[4096];
size_t len;
if (redis_sock_gets(redis_sock, inbuf, sizeof(inbuf) - 1, &len) < 0 ||
*inbuf != TYPE_MULTIBULK || atoi(inbuf + 1) < 0
) {
return FAILURE;
}
array_init(z_tab);
return redis_sock_read_multibulk_multi_reply_loop(INTERNAL_FUNCTION_PARAM_PASSTHRU,
redis_sock, z_tab);
}
/* exec */
PHP_METHOD(Redis, exec)
{
RedisSock *redis_sock;
int ret;
zval *object, z_ret;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
"O", &object, redis_ce) == FAILURE ||
(redis_sock = redis_sock_get(object, 0)) == NULL
) {
RETURN_FALSE;
}
ZVAL_FALSE(&z_ret);
if (IS_MULTI(redis_sock)) {
if (IS_PIPELINE(redis_sock)) {
PIPELINE_ENQUEUE_COMMAND(RESP_EXEC_CMD, sizeof(RESP_EXEC_CMD) - 1);
REDIS_SAVE_CALLBACK(NULL, NULL);
REDIS_DISABLE_MODE(redis_sock, MULTI);
RETURN_ZVAL(getThis(), 1, 0);
}
SOCKET_WRITE_COMMAND(redis_sock, RESP_EXEC_CMD, sizeof(RESP_EXEC_CMD) - 1)
ret = redis_sock_read_multibulk_multi_reply(
INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, &z_ret);
free_reply_callbacks(redis_sock);
REDIS_DISABLE_MODE(redis_sock, MULTI);
redis_sock->watching = 0;
if (ret < 0) {
zval_dtor(&z_ret);
ZVAL_FALSE(&z_ret);
}
}
if (IS_PIPELINE(redis_sock)) {
if (redis_sock->pipeline_cmd == NULL) {
/* Empty array when no command was run. */
array_init(&z_ret);
} else {
if (redis_sock_write(redis_sock, ZSTR_VAL(redis_sock->pipeline_cmd),
ZSTR_LEN(redis_sock->pipeline_cmd)) < 0) {
ZVAL_FALSE(&z_ret);
} else {
array_init(&z_ret);
if (redis_sock_read_multibulk_multi_reply_loop(
INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, &z_ret) != SUCCESS) {
zval_dtor(&z_ret);
ZVAL_FALSE(&z_ret);
}
}
zend_string_release(redis_sock->pipeline_cmd);
redis_sock->pipeline_cmd = NULL;
}
free_reply_callbacks(redis_sock);
REDIS_DISABLE_MODE(redis_sock, PIPELINE);
}
RETURN_ZVAL(&z_ret, 0, 1);
}
PHP_REDIS_API int
redis_response_enqueued(RedisSock *redis_sock)
{
char *resp;
int resp_len, ret = FAILURE;
if ((resp = redis_sock_read(redis_sock, &resp_len)) != NULL) {
if (strncmp(resp, "+QUEUED", 7) == 0) {
ret = SUCCESS;
}
efree(resp);
}
return ret;
}
PHP_REDIS_API int
redis_sock_read_multibulk_multi_reply_loop(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, zval *z_tab)
{
fold_item *fi;
for (fi = redis_sock->head; fi; /* void */) {
if (fi->fun) {
fi->fun(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, fi->ctx);
fi = fi->next;
continue;
}
size_t len;
char inbuf[255];
if (redis_sock_gets(redis_sock, inbuf, sizeof(inbuf) - 1, &len) < 0 || strncmp(inbuf, "+OK", 3) != 0) {
return FAILURE;
}
while ((fi = fi->next) && fi->fun) {
if (redis_response_enqueued(redis_sock) != SUCCESS) {
return FAILURE;
}
}
if (redis_sock_gets(redis_sock, inbuf, sizeof(inbuf) - 1, &len) < 0) {
return FAILURE;
}
zval z_ret;
array_init(&z_ret);
add_next_index_zval(z_tab, &z_ret);
int num = atol(inbuf + 1);
if (num > 0 && redis_read_multibulk_recursive(redis_sock, num, 0, &z_ret) < 0) {
return FAILURE;
}
if (fi) fi = fi->next;
}
redis_sock->current = fi;
return SUCCESS;
}
PHP_METHOD(Redis, pipeline)
{
RedisSock *redis_sock;
zval *object;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
"O", &object, redis_ce) == FAILURE ||
(redis_sock = redis_sock_get(object, 0)) == NULL
) {
RETURN_FALSE;
}
/* User cannot enter MULTI mode if already in a pipeline */
if (IS_MULTI(redis_sock)) {
php_error_docref(NULL, E_ERROR, "Can't activate pipeline in multi mode!");
RETURN_FALSE;
}
/* Enable pipeline mode unless we're already in that mode in which case this
* is just a NO OP */
if (IS_ATOMIC(redis_sock)) {
/* NB : we keep the function fold, to detect the last function.
* We need the response format of the n - 1 command. So, we can delete
* when n > 2, the { 1 .. n - 2} commands */
REDIS_ENABLE_MODE(redis_sock, PIPELINE);
}
RETURN_ZVAL(getThis(), 1, 0);
}
/* {{{ proto long Redis::publish(string channel, string msg) */
PHP_METHOD(Redis, publish)
{
REDIS_PROCESS_KW_CMD("PUBLISH", redis_key_str_cmd, redis_long_response);
}
/* }}} */
/* {{{ proto void Redis::psubscribe(Array(pattern1, pattern2, ... patternN)) */
PHP_METHOD(Redis, psubscribe)
{
REDIS_PROCESS_KW_CMD("PSUBSCRIBE", redis_subscribe_cmd,
redis_subscribe_response);
}
/* }}} */
/* {{{ proto void Redis::ssubscribe(Array(shardchannel1, shardchannel2, ... shardchannelN)) */
PHP_METHOD(Redis, ssubscribe)
{
REDIS_PROCESS_KW_CMD("SSUBSCRIBE", redis_subscribe_cmd,
redis_subscribe_response);
}
/* }}} */
/* {{{ proto void Redis::subscribe(Array(channel1, channel2, ... channelN)) */
PHP_METHOD(Redis, subscribe) {
REDIS_PROCESS_KW_CMD("SUBSCRIBE", redis_subscribe_cmd,
redis_subscribe_response);
}
/**
* [ps]unsubscribe channel_0 channel_1 ... channel_n
* [ps]unsubscribe(array(channel_0, channel_1, ..., channel_n))
* response format :
* array(
* channel_0 => TRUE|FALSE,
* channel_1 => TRUE|FALSE,
* ...
* channel_n => TRUE|FALSE
* );
**/
PHP_METHOD(Redis, unsubscribe)
{
REDIS_PROCESS_KW_CMD("UNSUBSCRIBE", redis_unsubscribe_cmd,
redis_unsubscribe_response);
}
PHP_METHOD(Redis, punsubscribe)
{
REDIS_PROCESS_KW_CMD("PUNSUBSCRIBE", redis_unsubscribe_cmd,
redis_unsubscribe_response);
}
PHP_METHOD(Redis, sunsubscribe)
{
REDIS_PROCESS_KW_CMD("SUNSUBSCRIBE", redis_unsubscribe_cmd,
redis_unsubscribe_response);
}
/* {{{ proto string Redis::bgrewriteaof() */
PHP_METHOD(Redis, bgrewriteaof)
{
REDIS_PROCESS_KW_CMD("BGREWRITEAOF", redis_empty_cmd,
redis_boolean_response);
}
/* }}} */
/* {{{ public function slaveof(string $host = NULL, int $port = NULL): Redis|bool }}} */
PHP_METHOD(Redis, slaveof) {
REDIS_PROCESS_KW_CMD("SLAVEOF", redis_replicaof_cmd, redis_boolean_response);
}
/* }}} */
/* {{{ public function replicaof(string $host = NULL, int $port = NULL): Redis|bool }}} */
PHP_METHOD(Redis, replicaof) {
REDIS_PROCESS_KW_CMD("REPLICAOF", redis_replicaof_cmd, redis_boolean_response);
}
/* }}} */
/* {{{ proto string Redis::object(key) */
PHP_METHOD(Redis, object)
{
REDIS_PROCESS_CMD(object, redis_object_response);
}
/* }}} */
/* {{{ proto string Redis::getOption($option) */
PHP_METHOD(Redis, getOption)
{
RedisSock *redis_sock;
if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
RETURN_FALSE;
}
redis_getoption_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL);
}
/* }}} */
/* {{{ proto string Redis::setOption(string $option, mixed $value) */
PHP_METHOD(Redis, setOption)
{
RedisSock *redis_sock;
if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
RETURN_FALSE;
}
redis_setoption_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL);
}
/* }}} */
/* {{{ proto boolean Redis::config(string op, string key [, mixed value]) */
/* {{{ proto public function config(string $op, string ...$args) }}} */
// CONFIG SET/GET
PHP_METHOD(Redis, config) {
REDIS_PROCESS_CMD(config, redis_config_response);
}
/* }}} */
/* {{{ proto boolean Redis::slowlog(string arg, [int option]) */
PHP_METHOD(Redis, slowlog) {
REDIS_PROCESS_CMD(slowlog, redis_read_variant_reply);
}
/* {{{ proto Redis::wait(int num_slaves, int ms) }}} */
PHP_METHOD(Redis, wait) {
REDIS_PROCESS_KW_CMD("WAIT", redis_long_long_cmd, redis_long_response);
}
/*
* {{{ proto Redis::pubsub("channels", pattern);
* proto Redis::pubsub("numsub", Array channels);
* proto Redis::pubsub("numpat"); }}}
*/
PHP_METHOD(Redis, pubsub) {
REDIS_PROCESS_CMD(pubsub, redis_pubsub_response);
}
/* {{{ proto variant Redis::eval(string script, [array keys, long num_keys]) */
PHP_METHOD(Redis, eval) {
REDIS_PROCESS_KW_CMD("EVAL", redis_eval_cmd, redis_read_raw_variant_reply);
}
/* {{{ proto variant Redis::eval_ro(string script, [array keys, long num_keys]) */
PHP_METHOD(Redis, eval_ro) {
REDIS_PROCESS_KW_CMD("EVAL_RO", redis_eval_cmd, redis_read_raw_variant_reply);
}
/* {{{ proto variant Redis::evalsha(string sha1, [array keys, long num_keys]) */
PHP_METHOD(Redis, evalsha) {
REDIS_PROCESS_KW_CMD("EVALSHA", redis_eval_cmd, redis_read_raw_variant_reply);
}
/* {{{ proto variant Redis::evalsha_ro(string sha1, [array keys, long num_keys]) */
PHP_METHOD(Redis, evalsha_ro) {
REDIS_PROCESS_KW_CMD("EVALSHA_RO", redis_eval_cmd, redis_read_raw_variant_reply);
}
/* {{{ proto variant Redis::fcall(string fn [, array keys [, array args]]) */
PHP_METHOD(Redis, fcall) {
REDIS_PROCESS_KW_CMD("FCALL", redis_fcall_cmd, redis_read_raw_variant_reply);
}
/* {{{ proto variant Redis::fcall_ro(string fn [, array keys [, array args]]) */
PHP_METHOD(Redis, fcall_ro) {
REDIS_PROCESS_KW_CMD("FCALL_RO", redis_fcall_cmd, redis_read_raw_variant_reply);
}
/* {{{ public function script($args...): mixed }}} */
PHP_METHOD(Redis, script) {
REDIS_PROCESS_CMD(script, redis_read_variant_reply);
}
/* {{{ proto DUMP key */
PHP_METHOD(Redis, dump) {
REDIS_PROCESS_KW_CMD("DUMP", redis_key_cmd, redis_string_response);
}
/* }}} */
/* {{{ proto Redis::restore(ttl, key, value) */
PHP_METHOD(Redis, restore) {
REDIS_PROCESS_CMD(restore, redis_boolean_response);
}
/* }}} */
/* {{{ proto Redis::debug(string key) */
PHP_METHOD(Redis, debug) {
REDIS_PROCESS_KW_CMD("DEBUG", redis_key_cmd, redis_string_response);
}
/* }}} */
/* {{{ proto Redis::migrate(host port key dest-db timeout [bool copy,
* bool replace]) */
PHP_METHOD(Redis, migrate) {
REDIS_PROCESS_CMD(migrate, redis_boolean_response);
}
/* {{{ proto Redis::_prefix(key) */
PHP_METHOD(Redis, _prefix) {
RedisSock *redis_sock;
if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
RETURN_FALSE;
}
redis_prefix_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock);
}
/* {{{ proto Redis::_serialize(value) */
PHP_METHOD(Redis, _serialize) {
RedisSock *redis_sock;
// Grab socket
if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
RETURN_FALSE;
}
redis_serialize_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock);
}
/* {{{ proto Redis::_unserialize(value) */
PHP_METHOD(Redis, _unserialize) {
RedisSock *redis_sock;
// Grab socket
if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
RETURN_FALSE;
}
redis_unserialize_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock,
redis_exception_ce);
}
PHP_METHOD(Redis, _compress) {
RedisSock *redis_sock;
// Grab socket
if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
RETURN_FALSE;
}
redis_compress_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock);
}
PHP_METHOD(Redis, _uncompress) {
RedisSock *redis_sock;
// Grab socket
if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
RETURN_FALSE;
}
redis_uncompress_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock,
redis_exception_ce);
}
PHP_METHOD(Redis, _pack) {
RedisSock *redis_sock;
// Grab socket
if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
RETURN_FALSE;
}
redis_pack_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock);
}
PHP_METHOD(Redis, _unpack) {
RedisSock *redis_sock;
// Grab socket
if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
RETURN_FALSE;
}
redis_unpack_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock);
}
/* {{{ proto Redis::getLastError() */
PHP_METHOD(Redis, getLastError) {
zval *object;
RedisSock *redis_sock;
// Grab our object
if(zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
&object, redis_ce) == FAILURE)
{
RETURN_FALSE;
}
// Grab socket
if ((redis_sock = redis_sock_get_instance(object, 0)) == NULL) {
RETURN_FALSE;
}
/* Return our last error or NULL if we don't have one */
if (redis_sock->err) {
RETURN_STRINGL(ZSTR_VAL(redis_sock->err), ZSTR_LEN(redis_sock->err));
}
RETURN_NULL();
}
/* {{{ proto Redis::clearLastError() */
PHP_METHOD(Redis, clearLastError) {
zval *object;
RedisSock *redis_sock;
// Grab our object
if(zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
&object, redis_ce) == FAILURE)
{
RETURN_FALSE;
}
// Grab socket
if ((redis_sock = redis_sock_get_instance(object, 0)) == NULL) {
RETURN_FALSE;
}
// Clear error message
if (redis_sock->err) {
zend_string_release(redis_sock->err);
redis_sock->err = NULL;
}
RETURN_TRUE;
}
/*
* {{{ proto long Redis::getMode()
*/
PHP_METHOD(Redis, getMode) {
zval *object;
RedisSock *redis_sock;
/* Grab our object */
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &object, redis_ce) == FAILURE) {
RETURN_FALSE;
}
/* Grab socket */
if ((redis_sock = redis_sock_get_instance(object, 0)) == NULL) {
RETURN_FALSE;
}
if (IS_PIPELINE(redis_sock)) {
RETVAL_LONG(PIPELINE);
} else if (IS_MULTI(redis_sock)) {
RETVAL_LONG(MULTI);
} else {
RETVAL_LONG(ATOMIC);
}
}
/* {{{ proto Redis::time() */
PHP_METHOD(Redis, time) {
REDIS_PROCESS_KW_CMD("TIME", redis_empty_cmd, redis_mbulk_reply_raw);
}
/* {{{ proto array Redis::role() */
PHP_METHOD(Redis, role) {
REDIS_PROCESS_KW_CMD("ROLE", redis_empty_cmd, redis_read_variant_reply);
}
/*
* Introspection stuff
*/
/* {{{ proto Redis::IsConnected */
PHP_METHOD(Redis, isConnected) {
zval *object;
RedisSock *redis_sock;
/* Grab our object */
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &object, redis_ce) == FAILURE) {
RETURN_FALSE;
}
/* Grab socket */
if ((redis_sock = redis_sock_get_instance(object, 1)) == NULL) {
RETURN_FALSE;
}
RETURN_BOOL(redis_sock->status >= REDIS_SOCK_STATUS_CONNECTED);
}
/* {{{ proto Redis::getHost() */
PHP_METHOD(Redis, getHost) {
RedisSock *redis_sock;
if((redis_sock = redis_sock_get_connected(INTERNAL_FUNCTION_PARAM_PASSTHRU))) {
RETURN_STRINGL(ZSTR_VAL(redis_sock->host), ZSTR_LEN(redis_sock->host));
} else {
RETURN_FALSE;
}
}
/* {{{ proto Redis::getPort() */
PHP_METHOD(Redis, getPort) {
RedisSock *redis_sock;
if((redis_sock = redis_sock_get_connected(INTERNAL_FUNCTION_PARAM_PASSTHRU))) {
/* Return our port */
RETURN_LONG(redis_sock->port);
} else {
RETURN_FALSE;
}
}
/* {{{ proto Redis::getDBNum */
PHP_METHOD(Redis, getDBNum) {
RedisSock *redis_sock;
if((redis_sock = redis_sock_get_connected(INTERNAL_FUNCTION_PARAM_PASSTHRU))) {
/* Return our db number */
RETURN_LONG(redis_sock->dbNumber);
} else {
RETURN_FALSE;
}
}
PHP_METHOD(Redis, getTransferredBytes) {
RedisSock *redis_sock;
if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
RETURN_THROWS();
}
array_init_size(return_value, 2);
add_next_index_long(return_value, redis_sock->txBytes);
add_next_index_long(return_value, redis_sock->rxBytes);
}
PHP_METHOD(Redis, clearTransferredBytes) {
RedisSock *redis_sock;
if ((redis_sock = redis_sock_get_instance(getThis(), 0)) == NULL) {
RETURN_THROWS();
}
redis_sock->txBytes = 0;
redis_sock->rxBytes = 0;
}
/* {{{ proto Redis::getTimeout */
PHP_METHOD(Redis, getTimeout) {
RedisSock *redis_sock;
if((redis_sock = redis_sock_get_connected(INTERNAL_FUNCTION_PARAM_PASSTHRU))) {
RETURN_DOUBLE(redis_sock->timeout);
} else {
RETURN_FALSE;
}
}
/* {{{ proto Redis::getReadTimeout */
PHP_METHOD(Redis, getReadTimeout) {
RedisSock *redis_sock;
if((redis_sock = redis_sock_get_connected(INTERNAL_FUNCTION_PARAM_PASSTHRU))) {
RETURN_DOUBLE(redis_sock->read_timeout);
} else {
RETURN_FALSE;
}
}
/* {{{ proto Redis::getPersistentID */
PHP_METHOD(Redis, getPersistentID) {
RedisSock *redis_sock;
if ((redis_sock = redis_sock_get_connected(INTERNAL_FUNCTION_PARAM_PASSTHRU)) == NULL) {
RETURN_FALSE;
} else if (redis_sock->persistent_id == NULL) {
RETURN_NULL();
}
RETURN_STRINGL(ZSTR_VAL(redis_sock->persistent_id), ZSTR_LEN(redis_sock->persistent_id));
}
/* {{{ proto Redis::getAuth */
PHP_METHOD(Redis, getAuth) {
RedisSock *redis_sock;
zval zret;
if (zend_parse_parameters_none() == FAILURE) {
RETURN_FALSE;
}
redis_sock = redis_sock_get_connected(INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (redis_sock == NULL)
RETURN_FALSE;
if (redis_sock->user && redis_sock->pass) {
array_init(&zret);
add_next_index_str(&zret, zend_string_copy(redis_sock->user));
add_next_index_str(&zret, zend_string_copy(redis_sock->pass));
RETURN_ZVAL(&zret, 0, 0);
} else if (redis_sock->pass) {
RETURN_STR_COPY(redis_sock->pass);
} else {
RETURN_NULL();
}
}
/* {{{ proto mixed Redis::client(string $command, [ $arg1 ... $argN]) */
PHP_METHOD(Redis, client) {
REDIS_PROCESS_CMD(client, redis_client_response);
}
/* }}} */
/* {{{ proto mixed Redis::rawcommand(string $command, [ $arg1 ... $argN]) */
PHP_METHOD(Redis, rawcommand) {
int argc = ZEND_NUM_ARGS(), cmd_len;
char *cmd = NULL;
RedisSock *redis_sock;
zval *z_args;
/* Sanity check on arguments */
if (argc < 1) {
php_error_docref(NULL, E_WARNING,
"Must pass at least one command keyword");
RETURN_FALSE;
}
z_args = emalloc(argc * sizeof(zval));
if (zend_get_parameters_array(ht, argc, z_args) == FAILURE) {
php_error_docref(NULL, E_WARNING,
"Internal PHP error parsing arguments");
efree(z_args);
RETURN_FALSE;
} else if (redis_build_raw_cmd(z_args, argc, &cmd, &cmd_len) < 0 ||
(redis_sock = redis_sock_get(getThis(), 0)) == NULL
) {
if (cmd) efree(cmd);
efree(z_args);
RETURN_FALSE;
}
/* Clean up command array */
efree(z_args);
/* Execute our command */
REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len);
if (IS_ATOMIC(redis_sock)) {
redis_read_raw_variant_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU,redis_sock,NULL,NULL);
}
REDIS_PROCESS_RESPONSE(redis_read_variant_reply);
}
/* }}} */
/* {{{ proto array Redis::command()
* proto array Redis::command('info', string cmd)
* proto array Redis::command('getkeys', array cmd_args) */
PHP_METHOD(Redis, command) {
REDIS_PROCESS_CMD(command, redis_command_response);
}
/* }}} */
/* {{{ proto array Redis::copy(string $source, string $destination, array $options = null) */
PHP_METHOD(Redis, copy) {
REDIS_PROCESS_CMD(copy, redis_1_response)
}
/* }}} */
/* Helper to format any combination of SCAN arguments */
PHP_REDIS_API int
redis_build_scan_cmd(char **cmd, REDIS_SCAN_TYPE type, char *key, int key_len,
long iter, char *pattern, int pattern_len, int count,
zend_string *match_type)
{
smart_string cmdstr = {0};
char *keyword;
int argc;
/* Count our arguments +1 for key if it's got one, and + 2 for pattern */
/* or count given that they each carry keywords with them. */
argc = 1 + (key_len > 0) + (pattern_len > 0 ? 2 : 0) + (count > 0 ? 2 : 0) + (match_type ? 2 : 0);
/* Turn our type into a keyword */
switch(type) {
case TYPE_SCAN:
keyword = "SCAN";
break;
case TYPE_SSCAN:
keyword = "SSCAN";
break;
case TYPE_HSCAN:
keyword = "HSCAN";
break;
case TYPE_ZSCAN:
default:
keyword = "ZSCAN";
break;
}
/* Start the command */
redis_cmd_init_sstr(&cmdstr, argc, keyword, strlen(keyword));
if (key_len) redis_cmd_append_sstr(&cmdstr, key, key_len);
redis_cmd_append_sstr_long(&cmdstr, iter);
/* Append COUNT if we've got it */
if(count) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "COUNT");
redis_cmd_append_sstr_int(&cmdstr, count);
}
/* Append MATCH if we've got it */
if(pattern_len) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "MATCH");
redis_cmd_append_sstr(&cmdstr, pattern, pattern_len);
}
if (match_type) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "TYPE");
redis_cmd_append_sstr(&cmdstr, ZSTR_VAL(match_type), ZSTR_LEN(match_type));
}
/* Return our command length */
*cmd = cmdstr.c;
return cmdstr.len;
}
/* {{{ proto redis::scan(&$iterator, [pattern, [count, [type]]]) */
PHP_REDIS_API void
generic_scan_cmd(INTERNAL_FUNCTION_PARAMETERS, REDIS_SCAN_TYPE type) {
zval *object, *z_iter;
RedisSock *redis_sock;
HashTable *hash;
char *pattern = NULL, *cmd, *key = NULL;
int cmd_len, num_elements, key_free = 0, pattern_free = 0;
size_t key_len = 0, pattern_len = 0;
zend_string *match_type = NULL;
zend_long count = 0, iter;
/* Different prototype depending on if this is a key based scan */
if(type != TYPE_SCAN) {
// Requires a key
if(zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
"Os!z/|s!l", &object, redis_ce, &key,
&key_len, &z_iter, &pattern,
&pattern_len, &count)==FAILURE)
{
RETURN_FALSE;
}
} else {
// Doesn't require a key
if(zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
"Oz/|s!lS!", &object, redis_ce, &z_iter,
&pattern, &pattern_len, &count, &match_type)
== FAILURE)
{
RETURN_FALSE;
}
}
/* Grab our socket */
if ((redis_sock = redis_sock_get(object, 0)) == NULL) {
RETURN_FALSE;
}
/* Calling this in a pipeline makes no sense */
if (!IS_ATOMIC(redis_sock)) {
php_error_docref(NULL, E_ERROR,
"Can't call SCAN commands in multi or pipeline mode!");
RETURN_FALSE;
}
// The iterator should be passed in as NULL for the first iteration, but we
// can treat any NON LONG value as NULL for these purposes as we've
// separated the variable anyway.
if(Z_TYPE_P(z_iter) != IS_LONG || Z_LVAL_P(z_iter) < 0) {
/* Convert to long */
convert_to_long(z_iter);
iter = 0;
} else if(Z_LVAL_P(z_iter) != 0) {
/* Update our iterator value for the next passthru */
iter = Z_LVAL_P(z_iter);
} else {
/* We're done, back to iterator zero */
RETURN_FALSE;
}
/* Prefix our key if we've got one and we have a prefix set */
if(key_len) {
key_free = redis_key_prefix(redis_sock, &key, &key_len);
}
if (redis_sock->scan & REDIS_SCAN_PREFIX) {
pattern_free = redis_key_prefix(redis_sock, &pattern, &pattern_len);
}
/**
* Redis can return to us empty keys, especially in the case where there
* are a large number of keys to scan, and we're matching against a
* pattern. phpredis can be set up to abstract this from the user, by
* setting OPT_SCAN to REDIS_SCAN_RETRY. Otherwise we will return empty
* keys and the user will need to make subsequent calls with an updated
* iterator.
*/
do {
/* Free our previous reply if we're back in the loop. We know we are
* if our return_value is an array */
if (Z_TYPE_P(return_value) == IS_ARRAY) {
zval_dtor(return_value);
ZVAL_NULL(return_value);
}
// Format our SCAN command
cmd_len = redis_build_scan_cmd(&cmd, type, key, key_len, (long)iter,
pattern, pattern_len, count, match_type);
/* Execute our command getting our new iterator value */
REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len);
if(redis_sock_read_scan_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU,
redis_sock,type,&iter) < 0)
{
if(key_free) efree(key);
RETURN_FALSE;
}
/* Get the number of elements */
hash = Z_ARRVAL_P(return_value);
num_elements = zend_hash_num_elements(hash);
} while (redis_sock->scan & REDIS_SCAN_RETRY && iter != 0 &&
num_elements == 0);
/* Free our pattern if it was prefixed */
if (pattern_free) efree(pattern);
/* Free our key if it was prefixed */
if(key_free) efree(key);
/* Update our iterator reference */
Z_LVAL_P(z_iter) = iter;
}
PHP_METHOD(Redis, scan) {
generic_scan_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, TYPE_SCAN);
}
PHP_METHOD(Redis, hscan) {
generic_scan_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, TYPE_HSCAN);
}
PHP_METHOD(Redis, sscan) {
generic_scan_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, TYPE_SSCAN);
}
PHP_METHOD(Redis, zscan) {
generic_scan_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, TYPE_ZSCAN);
}
/*
* HyperLogLog based commands
*/
/* {{{ proto Redis::pfAdd(string key, array elements) }}} */
PHP_METHOD(Redis, pfadd) {
REDIS_PROCESS_CMD(pfadd, redis_long_response);
}
/* {{{ proto Redis::pfCount(string key) }}}*/
PHP_METHOD(Redis, pfcount) {
REDIS_PROCESS_CMD(pfcount, redis_long_response);
}
/* {{{ proto Redis::pfMerge(string dstkey, array keys) }}}*/
PHP_METHOD(Redis, pfmerge) {
REDIS_PROCESS_CMD(pfmerge, redis_boolean_response);
}
/*
* Geo commands
*/
PHP_METHOD(Redis, geoadd) {
REDIS_PROCESS_CMD(geoadd, redis_long_response);
}
PHP_METHOD(Redis, geohash) {
REDIS_PROCESS_KW_CMD("GEOHASH", redis_key_varval_cmd, redis_mbulk_reply_raw);
}
PHP_METHOD(Redis, geopos) {
REDIS_PROCESS_KW_CMD("GEOPOS", redis_key_varval_cmd, redis_read_variant_reply);
}
PHP_METHOD(Redis, geodist) {
REDIS_PROCESS_CMD(geodist, redis_bulk_double_response);
}
PHP_METHOD(Redis, georadius) {
REDIS_PROCESS_KW_CMD("GEORADIUS", redis_georadius_cmd, redis_read_variant_reply);
}
PHP_METHOD(Redis, georadius_ro) {
REDIS_PROCESS_KW_CMD("GEORADIUS_RO", redis_georadius_cmd, redis_read_variant_reply);
}
PHP_METHOD(Redis, georadiusbymember) {
REDIS_PROCESS_KW_CMD("GEORADIUSBYMEMBER", redis_georadiusbymember_cmd, redis_read_variant_reply);
}
PHP_METHOD(Redis, georadiusbymember_ro) {
REDIS_PROCESS_KW_CMD("GEORADIUSBYMEMBER_RO", redis_georadiusbymember_cmd, redis_read_variant_reply);
}
PHP_METHOD(Redis, geosearch) {
REDIS_PROCESS_CMD(geosearch, redis_geosearch_response);
}
PHP_METHOD(Redis, geosearchstore) {
REDIS_PROCESS_CMD(geosearchstore, redis_long_response);
}
/*
* Streams
*/
PHP_METHOD(Redis, xack) {
REDIS_PROCESS_CMD(xack, redis_long_response);
}
PHP_METHOD(Redis, xadd) {
REDIS_PROCESS_CMD(xadd, redis_read_variant_reply);
}
PHP_METHOD(Redis, xautoclaim) {
REDIS_PROCESS_CMD(xautoclaim, redis_xclaim_reply);
}
PHP_METHOD(Redis, xclaim) {
REDIS_PROCESS_CMD(xclaim, redis_xclaim_reply);
}
PHP_METHOD(Redis, xdel) {
REDIS_PROCESS_KW_CMD("XDEL", redis_key_str_arr_cmd, redis_long_response);
}
PHP_METHOD(Redis, xgroup) {
REDIS_PROCESS_CMD(xgroup, redis_read_variant_reply);
}
PHP_METHOD(Redis, xinfo) {
REDIS_PROCESS_CMD(xinfo, redis_xinfo_reply);
}
PHP_METHOD(Redis, xlen) {
REDIS_PROCESS_KW_CMD("XLEN", redis_key_cmd, redis_long_response);
}
PHP_METHOD(Redis, xpending) {
REDIS_PROCESS_CMD(xpending, redis_read_variant_reply_strings);
}
PHP_METHOD(Redis, xrange) {
REDIS_PROCESS_KW_CMD("XRANGE", redis_xrange_cmd, redis_xrange_reply);
}
PHP_METHOD(Redis, xread) {
REDIS_PROCESS_CMD(xread, redis_xread_reply);
}
PHP_METHOD(Redis, xreadgroup) {
REDIS_PROCESS_CMD(xreadgroup, redis_xread_reply);
}
PHP_METHOD(Redis, xrevrange) {
REDIS_PROCESS_KW_CMD("XREVRANGE", redis_xrange_cmd, redis_xrange_reply);
}
PHP_METHOD(Redis, xtrim) {
REDIS_PROCESS_CMD(xtrim, redis_long_response);
}
/* vim: set tabstop=4 softtabstop=4 expandtab shiftwidth=4: */
redis-6.0.2/redis.stub.php 0000644 0001750 0000012 00000544247 14515245367 016233 0 ustar pyatsukhnenko wheel 'localhost',
* 'port' => 6379,
* 'readTimeout' => 2.5,
* 'connectTimeout' => 2.5,
* 'persistent' => true,
*
* // Valid formats: NULL, ['user', 'pass'], 'pass', or ['pass']
* 'auth' => ['phpredis', 'phpredis'],
*
* // See PHP stream options for valid SSL configuration settings.
* 'ssl' => ['verify_peer' => false],
*
* // How quickly to retry a connection after we time out or it closes.
* // Note that this setting is overridden by 'backoff' strategies.
* 'retryInterval' => 100,
*
* // Which backoff algorithm to use. 'decorrelated jitter' is
* // likely the best one for most solution, but there are many
* // to choose from:
* // REDIS_BACKOFF_ALGORITHM_DEFAULT
* // REDIS_BACKOFF_ALGORITHM_CONSTANT
* // REDIS_BACKOFF_ALGORITHM_UNIFORM
* // REDIS_BACKOFF_ALGORITHM_EXPONENTIAL
* // REDIS_BACKOFF_ALGORITHM_FULL_JITTER
* // REDIS_BACKOFF_ALGORITHM_EQUAL_JITTER
* // REDIS_BACKOFF_ALGORITHM_DECORRELATED_JITTER
* // 'base', and 'cap' are in milliseconds and represent the first
* // delay redis will use when reconnecting, and the maximum delay
* // we will reach while retrying.
* 'backoff' => [
* 'algorithm' => Redis::BACKOFF_ALGORITHM_DECORRELATED_JITTER,
* 'base' => 500,
* 'cap' => 750,
* ]
* ];
*
* Note: If you do wish to connect via the constructor, only 'host' is
* strictly required, which will cause PhpRedis to connect to that
* host on Redis' default port (6379).
*
*
* @see Redis::connect()
* @see https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/
* @param array $options
*
* @return Redis
*/
public function __construct(?array $options = null);
public function __destruct();
/**
* Compress a value with the currently configured compressor as set with
* Redis::setOption().
*
* @see Redis::setOption()
*
* @param string $value The value to be compressed
* @return string The compressed result
*
*/
public function _compress(string $value): string;
/**
* Uncompress the provided argument that has been compressed with the
* currently configured compressor as set with Redis::setOption().
*
* @see Redis::setOption()
*
* @param string $value The compressed value to uncompress.
* @return string The uncompressed result.
*
*/
public function _uncompress(string $value): string;
/**
* Prefix the passed argument with the currently set key prefix as set
* with Redis::setOption().
*
* @param string $key The key/string to prefix
* @return string The prefixed string
*
*/
public function _prefix(string $key): string;
/**
* Serialize the provided value with the currently set serializer as set
* with Redis::setOption().
*
* @see Redis::setOption()
*
* @param mixed $value The value to serialize
* @return string The serialized result
*
*/
public function _serialize(mixed $value): string;
/**
* Unserialize the passed argument with the currently set serializer as set
* with Redis::setOption().
*
* @see Redis::setOption()
*
* @param string $value The value to unserialize
* @return mixed The unserialized result
*
*/
public function _unserialize(string $value): mixed;
/**
* Pack the provided value with the configured serializer and compressor
* as set with Redis::setOption().
*
* @param mixed $value The value to pack
* @return string The packed result having been serialized and
* compressed.
*/
public function _pack(mixed $value): string;
/**
* Unpack the provided value with the configured compressor and serializer
* as set with Redis::setOption().
*
* @param string $value The value which has been serialized and compressed.
* @return mixed The uncompressed and eserialized value.
*
*/
public function _unpack(string $value): mixed;
public function acl(string $subcmd, string ...$args): mixed;
/**
* Append data to a Redis STRING key.
*
* @param string $key The key in question
* @param mixed $value The data to append to the key.
*
* @return Redis|int|false The new string length of the key or false on failure.
*
* @see https://redis.io/commands/append
*
* @example
* $redis->set('foo', 'hello);
* $redis->append('foo', 'world');
*/
public function append(string $key, mixed $value): Redis|int|false;
/**
* Authenticate a Redis connection after its been established.
*
* $redis->auth('password');
* $redis->auth(['password']);
* $redis->auth(['username', 'password']);
*
* @see https://redis.io/commands/auth
*
* @param mixed $credentials A string password, or an array with one or two string elements.
* @return Redis|bool Whether the AUTH was successful.
*
*/
public function auth(#[\SensitiveParameter] mixed $credentials): Redis|bool;
/**
* Execute a save of the Redis database in the background.
*
* @see https://redis.io/commands/bgsave
*
* @return Redis|bool Whether the command was successful.
*/
public function bgSave(): Redis|bool;
/**
* Asynchronously rewrite Redis' append-only file
*
* @see https://redis.io/commands/bgrewriteaof
*
* @return Redis|bool Whether the command was successful.
*/
public function bgrewriteaof(): Redis|bool;
/**
* Count the number of set bits in a Redis string.
*
* @see https://redis.io/commands/bitcount/
*
* @param string $key The key in question (must be a string key)
* @param int $start The index where Redis should start counting. If omitted it
* defaults to zero, which means the start of the string.
* @param int $end The index where Redis should stop counting. If omitted it
* defaults to -1, meaning the very end of the string.
*
* @param bool $bybit Whether or not Redis should treat $start and $end as bit
* positions, rather than bytes.
*
* @return Redis|int|false The number of bits set in the requested range.
*
*/
public function bitcount(string $key, int $start = 0, int $end = -1, bool $bybit = false): Redis|int|false;
public function bitop(string $operation, string $deskey, string $srckey, string ...$other_keys): Redis|int|false;
/**
* Return the position of the first bit set to 0 or 1 in a string.
*
* @see https://redis.io/commands/bitpos/
*
* @param string $key The key to check (must be a string)
* @param bool $bit Whether to look for an unset (0) or set (1) bit.
* @param int $start Where in the string to start looking.
* @param int $end Where in the string to stop looking.
* @param bool $bybit If true, Redis will treat $start and $end as BIT values and not bytes, so if start
* was 0 and end was 2, Redis would only search the first two bits.
*
* @return Redis|int|false The position of the first set or unset bit.
**/
public function bitpos(string $key, bool $bit, int $start = 0, int $end = -1, bool $bybit = false): Redis|int|false;
/**
* Pop an element off the beginning of a Redis list or lists, potentially blocking up to a specified
* timeout. This method may be called in two distinct ways, of which examples are provided below.
*
* @see https://redis.io/commands/blpop/
*
* @param string|array $key_or_keys This can either be a string key or an array of one or more
* keys.
* @param string|float|int $timeout_or_key If the previous argument was a string key, this can either
* be an additional key, or the timeout you wish to send to
* the command.
*
* @return Redis|array|null|false Can return various things depending on command and data in Redis.
*
* @example
* $redis->blPop('list1', 'list2', 'list3', 1.5);
* $relay->blPop(['list1', 'list2', 'list3'], 1.5);
*/
public function blPop(string|array $key_or_keys, string|float|int $timeout_or_key, mixed ...$extra_args): Redis|array|null|false;
/**
* Pop an element off of the end of a Redis list or lists, potentially blocking up to a specified timeout.
* The calling convention is identical to Redis::blPop() so see that documentation for more details.
*
* @see https://redis.io/commands/brpop/
* @see Redis::blPop()
*
*/
public function brPop(string|array $key_or_keys, string|float|int $timeout_or_key, mixed ...$extra_args): Redis|array|null|false;
/**
* Pop an element from the end of a Redis list, pushing it to the beginning of another Redis list,
* optionally blocking up to a specified timeout.
*
* @see https://redis.io/commands/brpoplpush/
*
* @param string $src The source list
* @param string $dst The destination list
* @param int|float $timeout The number of seconds to wait. Note that you must be connected
* to Redis >= 6.0.0 to send a floating point timeout.
*
*/
public function brpoplpush(string $src, string $dst, int|float $timeout): Redis|string|false;
/**
* POP the maximum scoring element off of one or more sorted sets, blocking up to a specified
* timeout if no elements are available.
*
* Following are examples of the two main ways to call this method.
*
* **NOTE**: We reccomend calling this function with an array and a timeout as the other strategy
* may be deprecated in future versions of PhpRedis
*
* @see https://redis.io/commands/bzpopmax
*
* @param string|array $key_or_keys Either a string key or an array of one or more keys.
* @param string|int $timeout_or_key If the previous argument was an array, this argument
* must be a timeout value. Otherwise it could also be
* another key.
* @param mixed $extra_args Can consist of additional keys, until the last argument
* which needs to be a timeout.
*
* @return Redis|array|false The popped elements.
*
* @example
* $redis->bzPopMax('key1', 'key2', 'key3', 1.5);
* $redis->bzPopMax(['key1', 'key2', 'key3'], 1.5);
*/
public function bzPopMax(string|array $key, string|int $timeout_or_key, mixed ...$extra_args): Redis|array|false;
/**
* POP the minimum scoring element off of one or more sorted sets, blocking up to a specified timeout
* if no elements are available
*
* This command is identical in semantics to bzPopMax so please see that method for more information.
*
* @see https://redis.io/commands/bzpopmin
* @see Redis::bzPopMax()
*
*/
public function bzPopMin(string|array $key, string|int $timeout_or_key, mixed ...$extra_args): Redis|array|false;
/**
* POP one or more elements from one or more sorted sets, blocking up to a specified amount of time
* when no elements are available.
*
* @param float $timeout How long to block if there are no element available
* @param array $keys The sorted sets to pop from
* @param string $from The string 'MIN' or 'MAX' (case insensitive) telling Redis whether you wish to
* pop the lowest or highest scoring members from the set(s).
* @param int $count Pop up to how many elements.
*
* @return Redis|array|null|false This function will return an array of popped elements, or false
* depending on whether any elements could be popped within the
* specified timeout.
*
* NOTE: If Redis::OPT_NULL_MULTIBULK_AS_NULL is set to true via Redis::setOption(), this method will
* instead return NULL when Redis doesn't pop any elements.
*/
public function bzmpop(float $timeout, array $keys, string $from, int $count = 1): Redis|array|null|false;
/**
* POP one or more of the highest or lowest scoring elements from one or more sorted sets.
*
* @see https://redis.io/commands/zmpop
*
* @param array $keys One or more sorted sets
* @param string $from The string 'MIN' or 'MAX' (case insensitive) telling Redis whether you want to
* pop the lowest or highest scoring elements.
* @param int $count Pop up to how many elements at once.
*
* @return Redis|array|null|false An array of popped elements or false if none could be popped.
*/
public function zmpop(array $keys, string $from, int $count = 1): Redis|array|null|false;
/**
* Pop one or more elements from one or more Redis LISTs, blocking up to a specified timeout when
* no elements are available.
*
* @see https://redis.io/commands/blmpop
*
* @param float $timeout The number of seconds Redis will block when no elements are available.
* @param array $keys One or more Redis LISTs to pop from.
* @param string $from The string 'LEFT' or 'RIGHT' (case insensitive), telling Redis whether
* to pop elements from the beginning or end of the LISTs.
* @param int $count Pop up to how many elements at once.
*
* @return Redis|array|null|false One or more elements popped from the list(s) or false if all LISTs
* were empty.
*/
public function blmpop(float $timeout, array $keys, string $from, int $count = 1): Redis|array|null|false;
/**
* Pop one or more elements off of one or more Redis LISTs.
*
* @see https://redis.io/commands/lmpop
*
* @param array $keys An array with one or more Redis LIST key names.
* @param string $from The string 'LEFT' or 'RIGHT' (case insensitive), telling Redis whether to pop\
* elements from the beginning or end of the LISTs.
* @param int $count The maximum number of elements to pop at once.
*
* @return Redis|array|null|false One or more elements popped from the LIST(s) or false if all the LISTs
* were empty.
*
*/
public function lmpop(array $keys, string $from, int $count = 1): Redis|array|null|false;
/**
* Reset any last error on the connection to NULL
*
* @see Redis::getLastError()
* @return bool This should always return true or throw an exception if we're not connected.
*
* @example
* $redis = new Redis(['host' => 'localhost']);
* $redis->set('string', 'this_is_a_string');
* $redis->smembers('string');
* var_dump($redis->getLastError());
* $redis->clearLastError();
* var_dump($redis->getLastError());
*/
public function clearLastError(): bool;
public function client(string $opt, mixed ...$args): mixed;
public function close(): bool;
public function command(?string $opt = null, mixed ...$args): mixed;
/**
* Execute the Redis CONFIG command in a variety of ways.
*
* What the command does in particular depends on the `$operation` qualifier.
* Operations that PhpRedis supports are: RESETSTAT, REWRITE, GET, and SET.
*
* @param string $operation The CONFIG operation to execute (e.g. GET, SET, REWRITE).
* @param array|string|null $key_or_settings One or more keys or values.
* @param string $value The value if this is a `CONFIG SET` operation.
* @see https://redis.io/commands/config
*
* @example
* $redis->config('GET', 'timeout');
* $redis->config('GET', ['timeout', 'databases']);
* $redis->config('SET', 'timeout', 30);
* $redis->config('SET', ['timeout' => 30, 'loglevel' => 'warning']);
*/
public function config(string $operation, array|string|null $key_or_settings = null, ?string $value = null): mixed;
public function connect(string $host, int $port = 6379, float $timeout = 0, ?string $persistent_id = null,
int $retry_interval = 0, float $read_timeout = 0, ?array $context = null): bool;
/**
* Make a copy of a key.
*
* $redis = new Redis(['host' => 'localhost']);
*
* @param string $src The key to copy
* @param string $dst The name of the new key created from the source key.
* @param array $options An array with modifiers on how COPY should operate.
*
* $options = [
* 'REPLACE' => true|false # Whether to replace an existing key.
* 'DB' => int # Copy key to specific db.
* ];
*
*
* @return Redis|bool True if the copy was completed and false if not.
*
* @see https://redis.io/commands/copy
*
* @example
* $redis->pipeline()
* ->select(1)
* ->del('newkey')
* ->select(0)
* ->del('newkey')
* ->mset(['source1' => 'value1', 'exists' => 'old_value'])
* ->exec();
*
* var_dump($redis->copy('source1', 'newkey'));
* var_dump($redis->copy('source1', 'newkey', ['db' => 1]));
* var_dump($redis->copy('source1', 'exists'));
* var_dump($redis->copy('source1', 'exists', ['REPLACE' => true]));
*/
public function copy(string $src, string $dst, ?array $options = null): Redis|bool;
/**
* Return the number of keys in the currently selected Redis database.
*
* @see https://redis.io/commands/dbsize
*
* @return Redis|int The number of keys or false on failure.
*
* @example
* $redis = new Redis(['host' => 'localhost']);
* $redis->flushdb();
* $redis->set('foo', 'bar');
* var_dump($redis->dbsize());
* $redis->mset(['a' => 'a', 'b' => 'b', 'c' => 'c', 'd' => 'd']);
* var_dump($redis->dbsize());
*/
public function dbSize(): Redis|int|false;
public function debug(string $key): Redis|string;
/**
* Decrement a Redis integer by 1 or a provided value.
*
* @param string $key The key to decrement
* @param int $by How much to decrement the key. Note that if this value is
* not sent or is set to `1`, PhpRedis will actually invoke
* the 'DECR' command. If it is any value other than `1`
* PhpRedis will actually send the `DECRBY` command.
*
* @return Redis|int|false The new value of the key or false on failure.
*
* @see https://redis.io/commands/decr
* @see https://redis.io/commands/decrby
*
* @example $redis->decr('counter');
* @example $redis->decr('counter', 2);
*/
public function decr(string $key, int $by = 1): Redis|int|false;
/**
* Decrement a redis integer by a value
*
* @param string $key The integer key to decrement.
* @param int $value How much to decrement the key.
*
* @return Redis|int|false The new value of the key or false on failure.
*
* @see https://redis.io/commands/decrby
*
* @example $redis->decrby('counter', 1);
* @example $redis->decrby('counter', 2);
*/
public function decrBy(string $key, int $value): Redis|int|false;
/**
* Delete one or more keys from Redis.
*
* This method can be called in two distinct ways. The first is to pass a single array
* of keys to delete, and the second is to pass N arguments, all names of keys. See
* below for an example of both strategies.
*
* @param array|string $key_or_keys Either an array with one or more key names or a string with
* the name of a key.
* @param string $other_keys One or more additional keys passed in a variadic fashion.
*
* @return Redis|int|false The number of keys that were deleted
*
* @see https://redis.io/commands/del
*
* @example $redis->del('key:0', 'key:1');
* @example $redis->del(['key:2', 'key:3', 'key:4']);
*/
public function del(array|string $key, string ...$other_keys): Redis|int|false;
/**
* @deprecated
* @alias Redis::del
*/
public function delete(array|string $key, string ...$other_keys): Redis|int|false;
/**
* Discard a transaction currently in progress.
*
* @return Redis|bool True if we could discard the transaction.
*
* @example
* $redis->getMode();
* $redis->set('foo', 'bar');
* $redis->discard();
* $redis->getMode();
*/
public function discard(): Redis|bool;
/**
* Dump Redis' internal binary representation of a key.
*
* $redis->zRange('new-zset', 0, -1, true);
*
*
* @param string $key The key to dump.
*
* @return Redis|string A binary string representing the key's value.
*
* @see https://redis.io/commands/dump
*
* @example
* $redis->zadd('zset', 0, 'zero', 1, 'one', 2, 'two');
* $binary = $redis->dump('zset');
* $redis->restore('new-zset', 0, $binary);
*/
public function dump(string $key): Redis|string;
/**
* Have Redis repeat back an arbitrary string to the client.
*
* @param string $str The string to echo
*
* @return Redis|string|false The string sent to Redis or false on failure.
*
* @see https://redis.io/commands/echo
*
* @example $redis->echo('Hello, World');
*/
public function echo(string $str): Redis|string|false;
/**
* Execute a LUA script on the redis server.
*
* @see https://redis.io/commands/eval/
*
* @param string $script A string containing the LUA script
* @param array $args An array of arguments to pass to this script
* @param int $num_keys How many of the arguments are keys. This is needed
* as redis distinguishes between key name arguments
* and other data.
*
* @return mixed LUA scripts may return arbitrary data so this method can return
* strings, arrays, nested arrays, etc.
*/
public function eval(string $script, array $args = [], int $num_keys = 0): mixed;
/**
* This is simply the read-only variant of eval, meaning the underlying script
* may not modify data in redis.
*
* @see Redis::eval_ro()
*/
public function eval_ro(string $script_sha, array $args = [], int $num_keys = 0): mixed;
/**
* Execute a LUA script on the server but instead of sending the script, send
* the SHA1 hash of the script.
*
* @param string $script_sha The SHA1 hash of the lua code. Note that the script
* must already exist on the server, either having been
* loaded with `SCRIPT LOAD` or having been executed directly
* with `EVAL` first.
* @param array $args Arguments to send to the script.
* @param int $num_keys The number of arguments that are keys
*
* @return mixed Returns whatever the specific script does.
*
* @see https://redis.io/commands/evalsha/
* @see Redis::eval();
*
*/
public function evalsha(string $sha1, array $args = [], int $num_keys = 0): mixed;
/**
* This is simply the read-only variant of evalsha, meaning the underlying script
* may not modify data in redis.
*
* @see Redis::evalsha()
*/
public function evalsha_ro(string $sha1, array $args = [], int $num_keys = 0): mixed;
/**
* Execute either a MULTI or PIPELINE block and return the array of replies.
*
* @return Redis|array|false The array of pipeline'd or multi replies or false on failure.
*
* @see https://redis.io/commands/exec
* @see https://redis.io/commands/multi
* @see Redis::pipeline()
* @see Redis::multi()
*
* @example
* $res = $redis->multi()
* ->set('foo', 'bar')
* ->get('foo')
* ->del('list')
* ->rpush('list', 'one', 'two', 'three')
* ->exec();
*/
public function exec(): Redis|array|false;
/**
* Test if one or more keys exist.
*
* @param mixed $key Either an array of keys or a string key
* @param mixed $other_keys If the previous argument was a string, you may send any number of
* additional keys to test.
*
* @return Redis|int|bool The number of keys that do exist and false on failure
*
* @see https://redis.io/commands/exists
*
* @example $redis->exists(['k1', 'k2', 'k3']);
* @example $redis->exists('k4', 'k5', 'notakey');
*/
public function exists(mixed $key, mixed ...$other_keys): Redis|int|bool;
/**
* Sets an expiration in seconds on the key in question. If connected to
* redis-server >= 7.0.0 you may send an additional "mode" argument which
* modifies how the command will execute.
*
* @param string $key The key to set an expiration on.
* @param int $timeout The number of seconds after which key will be automatically deleted.
* @param string|null $mode A two character modifier that changes how the
* command works.
*
* NX - Set expiry only if key has no expiry
* XX - Set expiry only if key has an expiry
* LT - Set expiry only when new expiry is < current expiry
* GT - Set expiry only when new expiry is > current expiry
*
*
* @return Redis|bool True if an expiration was set and false otherwise.
* @see https://redis.io/commands/expire
*
*/
public function expire(string $key, int $timeout, ?string $mode = null): Redis|bool;
/*
* Set a key's expiration to a specific Unix timestamp in seconds.
*
* If connected to Redis >= 7.0.0 you can pass an optional 'mode' argument.
* @see Redis::expire() For a description of the mode argument.
*
* @param string $key The key to set an expiration on.
*
* @return Redis|bool True if an expiration was set, false if not.
*
*/
/**
* Set a key to expire at an exact unix timestamp.
*
* @param string $key The key to set an expiration on.
* @param int $timestamp The unix timestamp to expire at.
* @param string|null $mode An option 'mode' that modifies how the command acts (see {@link Redis::expire}).
* @return Redis|bool True if an expiration was set, false if not.
*
* @see https://redis.io/commands/expireat
* @see https://redis.io/commands/expire
* @see Redis::expire()
*/
public function expireAt(string $key, int $timestamp, ?string $mode = null): Redis|bool;
public function failover(?array $to = null, bool $abort = false, int $timeout = 0): Redis|bool;
/**
* Get the expiration of a given key as a unix timestamp
*
* @param string $key The key to check.
*
* @return Redis|int|false The timestamp when the key expires, or -1 if the key has no expiry
* and -2 if the key doesn't exist.
*
* @see https://redis.io/commands/expiretime
*
* @example
* $redis->setEx('mykey', 60, 'myval');
* $redis->expiretime('mykey');
*/
public function expiretime(string $key): Redis|int|false;
/**
* Get the expriation timestamp of a given Redis key but in milliseconds.
*
* @see https://redis.io/commands/pexpiretime
* @see Redis::expiretime()
*
* @param string $key The key to check
*
* @return Redis|int|false The expiration timestamp of this key (in milliseconds) or -1 if the
* key has no expiration, and -2 if it does not exist.
*/
public function pexpiretime(string $key): Redis|int|false;
/**
* Invoke a function.
*
* @param string $fn The name of the function
* @param array $keys Optional list of keys
* @param array $args Optional list of args
*
* @return mixed Function may return arbitrary data so this method can return
* strings, arrays, nested arrays, etc.
*
* @see https://redis.io/commands/fcall
*/
public function fcall(string $fn, array $keys = [], array $args = []): mixed;
/**
* This is a read-only variant of the FCALL command that cannot execute commands that modify data.
*
* @param string $fn The name of the function
* @param array $keys Optional list of keys
* @param array $args Optional list of args
*
* @return mixed Function may return arbitrary data so this method can return
* strings, arrays, nested arrays, etc.
*
* @see https://redis.io/commands/fcall_ro
*/
public function fcall_ro(string $fn, array $keys = [], array $args = []): mixed;
/**
* Deletes every key in all Redis databases
*
* @param bool $sync Whether to perform the task in a blocking or non-blocking way.
* @return bool
*
* @see https://redis.io/commands/flushall
*/
public function flushAll(?bool $sync = null): Redis|bool;
/**
* Deletes all the keys of the currently selected database.
*
* @param bool $sync Whether to perform the task in a blocking or non-blocking way.
* @return bool
*
* @see https://redis.io/commands/flushdb
*/
public function flushDB(?bool $sync = null): Redis|bool;
/**
* Functions is an API for managing code to be executed on the server.
*
* @param string $operation The subcommand you intend to execute. Valid options are as follows
* 'LOAD' - Create a new library with the given library name and code.
* 'DELETE' - Delete the given library.
* 'LIST' - Return general information on all the libraries
* 'STATS' - Return information about the current function running
* 'KILL' - Kill the current running function
* 'FLUSH' - Delete all the libraries
* 'DUMP' - Return a serialized payload representing the current libraries
* 'RESTORE' - Restore the libraries represented by the given payload
* @param member $args Additional arguments
*
* @return Redis|bool|string|array Depends on subcommand.
*
* @see https://redis.io/commands/function
*/
public function function(string $operation, mixed ...$args): Redis|bool|string|array;
/**
* Add one or more members to a geospacial sorted set
*
* @param string $key The sorted set to add data to.
* @param float $lng The longitude of the first member
* @param float $lat The lattitude of the first member.
* @param member $other_triples_and_options You can continue to pass longitude, lattitude, and member
* arguments to add as many members as you wish. Optionally, the final argument may be
* a string with options for the command @see Redis documentation for the options.
*
* @return Redis|int|false The number of added elements is returned. If the 'CH' option is specified,
* the return value is the number of members *changed*.
*
* @example $redis->geoAdd('cities', -121.8374, 39.7284, 'Chico', -122.03218, 37.322, 'Cupertino');
* @example $redis->geoadd('cities', -121.837478, 39.728494, 'Chico', ['XX', 'CH']);
*
* @see https://redis.io/commands/geoadd
*/
public function geoadd(string $key, float $lng, float $lat, string $member, mixed ...$other_triples_and_options): Redis|int|false;
/**
* Get the distance between two members of a geospacially encoded sorted set.
*
* @param string $key The Sorted set to query.
* @param string $src The first member.
* @param string $dst The second member.
* @param string $unit Which unit to use when computing distance, defaulting to meters.
*
* M - meters
* KM - kilometers
* FT - feet
* MI - miles
*
*
* @return Redis|float|false The calculated distance in whichever units were specified or false
* if one or both members did not exist.
*
* @example $redis->geodist('cities', 'Chico', 'Cupertino', 'mi');
*
* @see https://redis.io/commands/geodist
*/
public function geodist(string $key, string $src, string $dst, ?string $unit = null): Redis|float|false;
/**
* Retrieve one or more GeoHash encoded strings for members of the set.
*
* @param string $key The key to query
* @param string $member The first member to request
* @param string $other_members One or more additional members to request.
*
* @return Redis|array|false An array of GeoHash encoded values.
*
* @see https://redis.io/commands/geohash
* @see https://en.wikipedia.org/wiki/Geohash
*
* @example $redis->geohash('cities', 'Chico', 'Cupertino');
*/
public function geohash(string $key, string $member, string ...$other_members): Redis|array|false;
/**
* Return the longitude and lattitude for one or more members of a geospacially encoded sorted set.
*
* @param string $key The set to query.
* @param string $member The first member to query.
* @param string $other_members One or more members to query.
*
* @return An array of longitude and lattitude pairs.
*
* @see https://redis.io/commands/geopos
*
* @example $redis->geopos('cities', 'Seattle', 'New York');
*/
public function geopos(string $key, string $member, string ...$other_members): Redis|array|false;
/**
* Retrieve members of a geospacially sorted set that are within a certain radius of a location.
*
* @param string $key The set to query
* @param float $lng The longitude of the location to query.
* @param float $lat The latitude of the location to query.
* @param float $radius The radius of the area to include.
* @param string $unit The unit of the provided radius (defaults to 'meters).
* See {@link Redis::geodist} for possible units.
* @param array $options An array of options that modifies how the command behaves.
*
* $options = [
* 'WITHCOORD', # Return members and their coordinates.
* 'WITHDIST', # Return members and their distances from the center.
* 'WITHHASH', # Return members GeoHash string.
* 'ASC' | 'DESC', # The sort order of returned members
*
* # Limit to N returned members. Optionally a two element array may be
* # passed as the `LIMIT` argument, and the `ANY` argument.
* 'COUNT' => [], or [, ]
*
* # Instead of returning members, store them in the specified key.
* 'STORE' =>
*
* # Store the distances in the specified key
* 'STOREDIST' =>
* ];
*
*
* @return mixed This command can return various things, depending on the options passed.
*
* @see https://redis.io/commands/georadius
*
* @example $redis->georadius('cities', 47.608013, -122.335167, 1000, 'km');
*/
public function georadius(string $key, float $lng, float $lat, float $radius, string $unit, array $options = []): mixed;
/**
* A readonly variant of `GEORADIUS` that may be executed on replicas.
*
* @see Redis::georadius
*/
public function georadius_ro(string $key, float $lng, float $lat, float $radius, string $unit, array $options = []): mixed;
/**
* Similar to `GEORADIUS` except it uses a member as the center of the query.
*
* @param string $key The key to query.
* @param string $member The member to treat as the center of the query.
* @param float $radius The radius from the member to include.
* @param string $unit The unit of the provided radius
* See {@link Redis::geodist} for possible units.
* @param array $options An array with various options to modify the command's behavior.
* See {@link Redis::georadius} for options.
*
* @return mixed This command can return various things depending on options.
*
* @example $redis->georadiusbymember('cities', 'Seattle', 200, 'mi');
*/
public function georadiusbymember(string $key, string $member, float $radius, string $unit, array $options = []): mixed;
/**
* This is the read-only variant of `GEORADIUSBYMEMBER` that can be run on replicas.
*/
public function georadiusbymember_ro(string $key, string $member, float $radius, string $unit, array $options = []): mixed;
/**
* Search a geospacial sorted set for members in various ways.
*
* @param string $key The set to query.
* @param array|string $position Either a two element array with longitude and lattitude, or
* a string representing a member of the set.
* @param array|int|float $shape Either a number representine the radius of a circle to search, or
* a two element array representing the width and height of a box
* to search.
* @param string $unit The unit of our shape. See {@link Redis::geodist} for possible units.
* @param array $options @see {@link Redis::georadius} for options. Note that the `STORE`
* options are not allowed for this command.
*/
public function geosearch(string $key, array|string $position, array|int|float $shape, string $unit, array $options = []): array;
/**
* Search a geospacial sorted set for members within a given area or range, storing the results into
* a new set.
*
* @param string $dst The destination where results will be stored.
* @param string $src The key to query.
* @param array|string $position Either a two element array with longitude and lattitude, or
* a string representing a member of the set.
* @param array|int|float $shape Either a number representine the radius of a circle to search, or
* a two element array representing the width and height of a box
* to search.
* @param string $unit The unit of our shape. See {@link Redis::geodist} for possible units.
* @param array $options
*
* $options = [
* 'ASC' | 'DESC', # The sort order of returned members
* 'WITHDIST' # Also store distances.
*
* # Limit to N returned members. Optionally a two element array may be
* # passed as the `LIMIT` argument, and the `ANY` argument.
* 'COUNT' => [], or [, ]
* ];
*
*/
public function geosearchstore(string $dst, string $src, array|string $position, array|int|float $shape, string $unit, array $options = []): Redis|array|int|false;
/**
* Retrieve a string keys value.
*
* @param string $key The key to query
* @return mixed The keys value or false if it did not exist.
*
* @see https://redis.io/commands/get
*
* @example $redis->get('foo');
*/
public function get(string $key): mixed;
/**
* Get the authentication information on the connection, if any.
*
* @return mixed The authentication information used to authenticate the connection.
*
* @see Redis::auth()
*/
public function getAuth(): mixed;
/**
* Get the bit at a given index in a string key.
*
* @param string $key The key to query.
* @param int $idx The Nth bit that we want to query.
*
* @example $redis->getbit('bitmap', 1337);
*
* @see https://redis.io/commands/getbit
*/
public function getBit(string $key, int $idx): Redis|int|false;
/**
* Get the value of a key and optionally set it's expiration.
*
* @param string $key The key to query
* @param array $options Options to modify how the command works.
*
* $options = [
* 'EX' => # Expire in N seconds
* 'PX' => # Expire in N milliseconds
* 'EXAT' => # Expire at a unix timestamp (in seconds)
* 'PXAT' => # Expire at a unix timestamp (in milliseconds);
* 'PERSIST' # Remove any configured expiration on the key.
* ];
*
*
* @return Redis|string|bool The key's value or false if it didn't exist.
*
* @see https://redis.io/comands/getex
*
* @example $redis->getEx('mykey', ['EX' => 60]);
*/
public function getEx(string $key, array $options = []): Redis|string|bool;
/**
* Get the database number PhpRedis thinks we're connected to.
*
* This value is updated internally in PhpRedis each time {@link Redis::select} is called.
*
* @return The database we're connected to.
*
* @see Redis::select()
* @see https://redis.io/commands/select
*/
public function getDBNum(): int;
/**
* Get a key from Redis and delete it in an atomic operation.
*
* @param string $key The key to get/delete.
* @return Redis|string|bool The value of the key or false if it didn't exist.
*
* @see https://redis.io/commands/getdel
*
* @example $redis->getdel('token:123');
*/
public function getDel(string $key): Redis|string|bool;
/**
* Return the host or Unix socket we are connected to.
*
* @return string The host or Unix socket.
*/
public function getHost(): string;
/**
* Get the last error returned to us from Redis, if any.
*
* @return string The error string or NULL if there is none.
*/
public function getLastError(): ?string;
/**
* Returns whether the connection is in ATOMIC, MULTI, or PIPELINE mode
*
* @return int The mode we're in.
*
*/
public function getMode(): int;
/**
* Retrieve the value of a configuration setting as set by Redis::setOption()
*
* @see Redis::setOption() for a detailed list of options and their values.
*
* @return mixed The setting itself or false on failure
*/
public function getOption(int $option): mixed;
/**
* Get the persistent connection ID, if there is one.
*
* @return string The ID or NULL if we don't have one.
*/
public function getPersistentID(): ?string;
/**
* Get the port we are connected to. This number will be zero if we are connected to a unix socket.
*
* @return int The port.
*/
public function getPort(): int;
/**
* Retrieve a substring of a string by index.
*
* @param string $key The string to query.
* @param int $start The zero-based starting index.
* @param int $end The zero-based ending index.
*
* @return Redis|string|false The substring or false on failure.
*
* @see https://redis.io/commands/getrange
*
* @example
* $redis->set('silly-word', 'Supercalifragilisticexpialidocious');
* echo $redis->getRange('silly-word', 0, 4) . "\n";
*/
public function getRange(string $key, int $start, int $end): Redis|string|false;
/**
* Get the longest common subsequence between two string keys.
*
* @param string $key1 The first key to check
* @param string $key2 The second key to check
* @param array $options An optional array of modifiers for the comand.
*
*
* $options = [
* 'MINMATCHLEN' => int # Exclude matching substrings that are less than this value
*
* 'WITHMATCHLEN' => bool # Whether each match should also include its length.
*
* 'LEN' # Return the length of the longest subsequence
*
* 'IDX' # Each returned match will include the indexes where the
* # match occurs in each string.
* ];
*
*
* NOTE: 'LEN' cannot be used with 'IDX'.
*
* @return Redis|string|array|int|false Various reply types depending on options.
*
* @see https://redis.io/commands/lcs
*
* @example
* $redis->set('seq1', 'gtaggcccgcacggtctttaatgtatccctgtttaccatgccatacctgagcgcatacgc');
* $redis->set('seq2', 'aactcggcgcgagtaccaggccaaggtcgttccagagcaaagactcgtgccccgctgagc');
* echo $redis->lcs('seq1', 'seq2') . "\n";
*/
public function lcs(string $key1, string $key2, ?array $options = null): Redis|string|array|int|false;
/**
* Get the currently set read timeout on the connection.
*
* @return float The timeout.
*/
public function getReadTimeout(): float;
/**
* Sets a key and returns any previously set value, if the key already existed.
*
* @param string $key The key to set.
* @param mixed $value The value to set the key to.
*
* @return Redis|string|false The old value of the key or false if it didn't exist.
*
* @see https://redis.io/commands/getset
*
* @example
* $redis->getset('captain', 'Pike');
* $redis->getset('captain', 'Kirk');
*/
public function getset(string $key, mixed $value): Redis|string|false;
/**
* Retrieve any set connection timeout
*
* @return float The currently set timeout or false on failure (e.g. we aren't connected).
*/
public function getTimeout(): float|false;
/**
* Get the number of bytes sent and received on the socket.
*
* @return array An array in the form [$sent_bytes, $received_bytes]
*/
public function getTransferredBytes(): array;
/**
* Reset the number of bytes sent and received on the socket.
*
* @return void
*/
public function clearTransferredBytes(): void;
/**
* Remove one or more fields from a hash.
*
* @param string $key The hash key in question.
* @param string $field The first field to remove
* @param string $other_fields One or more additional fields to remove.
*
* @return Redis|int|false The number of fields actually removed.
*
* @see https://redis.io/commands/hdel
*
* @example $redis->hDel('communication', 'Alice', 'Bob');
*/
public function hDel(string $key, string $field, string ...$other_fields): Redis|int|false;
/**
* Checks whether a field exists in a hash.
*
* @param string $key The hash to query.
* @param string $field The field to check
*
* @return Redis|bool True if it exists, false if not.
*
* @see https://redis.io/commands/hexists
*
* @example $redis->hExists('communication', 'Alice');
*/
public function hExists(string $key, string $field): Redis|bool;
public function hGet(string $key, string $member): mixed;
/**
* Read every field and value from a hash.
*
* @param string $key The hash to query.
* @return Redis|array|false All fields and values or false if the key didn't exist.
*
* @see https://redis.io/commands/hgetall
*
* @example $redis->hgetall('myhash');
*/
public function hGetAll(string $key): Redis|array|false;
/**
* Increment a hash field's value by an integer
*
* @param string $key The hash to modify
* @param string $field The field to increment
* @param int $value How much to increment the value.
*
* @return Redis|int|false The new value of the field.
*
* @see https://redis.io/commands/hincrby
*
* @example
* $redis->hMSet('player:1', ['name' => 'Alice', 'score' => 0]);
* $redis->hincrby('player:1', 'score', 10);
*
*/
public function hIncrBy(string $key, string $field, int $value): Redis|int|false;
/**
* Increment a hash field by a floating point value
*
* @param string $key The hash with the field to increment.
* @param string $field The field to increment.
*
* @return Redis|float|false The field value after incremented.
*
* @see https://redis.io/commands/hincrbyfloat
*
* @example
* $redis->hincrbyfloat('numbers', 'tau', 2 * 3.1415926);
*/
public function hIncrByFloat(string $key, string $field, float $value): Redis|float|false;
/**
* Retrieve all of the fields of a hash.
*
* @param string $key The hash to query.
*
* @return Redis|array|false The fields in the hash or false if the hash doesn't exist.
*
* @see https://redis.io/commands/hkeys
*
* @example $redis->hkeys('myhash');
*/
public function hKeys(string $key): Redis|array|false;
/**
* Get the number of fields in a hash.
*
* @see https://redis.io/commands/hlen
*
* @param string $key The hash to check.
*
* @return Redis|int|false The number of fields or false if the key didn't exist.
*
* @example $redis->hlen('myhash');
*/
public function hLen(string $key): Redis|int|false;
/**
* Get one or more fields from a hash.
*
* @param string $key The hash to query.
* @param array $fields One or more fields to query in the hash.
*
* @return Redis|array|false The fields and values or false if the key didn't exist.
*
* @see https://redis.io/commands/hmget
*
* @example $redis->hMGet('player:1', ['name', 'score']);
*/
public function hMget(string $key, array $fields): Redis|array|false;
/**
* Add or update one or more hash fields and values
*
* @param string $key The hash to create/update
* @param array $fieldvals An associative array with fields and their values.
*
* @return Redis|bool True if the operation was successful
*
* @see https://redis.io/commands/hmset
*
* @example $redis->hmset('updates', ['status' => 'starting', 'elapsed' => 0]);
*/
public function hMset(string $key, array $fieldvals): Redis|bool;
/**
* Get one or more random field from a hash.
*
* @param string $key The hash to query.
* @param array $options An array of options to modify how the command behaves.
*
*
* $options = [
* 'COUNT' => int # An optional number of fields to return.
* 'WITHVALUES' => bool # Also return the field values.
* ];
*
*
* @return Redis|array|string One or more random fields (and possibly values).
*
* @see https://redis.io/commands/hrandfield
*
* @example $redis->hrandfield('settings');
* @example $redis->hrandfield('settings', ['count' => 2, 'withvalues' => true]);
*/
public function hRandField(string $key, ?array $options = null): Redis|string|array;
public function hSet(string $key, string $member, mixed $value): Redis|int|false;
/**
* Set a hash field and value, but only if that field does not exist
*
* @param string $key The hash to update.
* @param string $field The value to set.
*
* @return Redis|bool True if the field was set and false if not.
*
* @see https://redis.io/commands/hsetnx
*
* @example
* $redis->hsetnx('player:1', 'lock', 'enabled');
* $redis->hsetnx('player:1', 'lock', 'enabled');
*/
public function hSetNx(string $key, string $field, string $value): Redis|bool;
/**
* Get the string length of a hash field
*
* @param string $key The hash to query.
* @param string $field The field to query.
*
* @return Redis|int|false The string length of the field or false.
*
* @example
* $redis = new Redis(['host' => 'localhost']);
* $redis->del('hash');
* $redis->hmset('hash', ['50bytes' => str_repeat('a', 50)]);
* $redis->hstrlen('hash', '50bytes');
*
* @see https://redis.io/commands/hstrlen
*/
public function hStrLen(string $key, string $field): Redis|int|false;
/**
* Get all of the values from a hash.
*
* @param string $key The hash to query.
*
* @return Redis|array|false The values from the hash.
*
* @see https://redis.io/commands/hvals
*
* @example $redis->hvals('player:1');
*/
public function hVals(string $key): Redis|array|false;
/**
* Iterate over the fields and values of a hash in an incremental fashion.
*
* @see https://redis.io/commands/hscan
* @see https://redis.io/commands/scan
*
* @param string $key The hash to query.
* @param int $iterator The scan iterator, which should be initialized to NULL before the first call.
* This value will be updated after every call to hscan, until it reaches zero
* meaning the scan is complete.
* @param string $pattern An optional glob-style pattern to filter fields with.
* @param int $count An optional hint to Redis about how many fields and values to return per HSCAN.
*
* @return Redis|array|bool An array with a subset of fields and values.
*
* @example
* $redis = new Redis(['host' => 'localhost']);
*
* $redis->del('big-hash');
*
* for ($i = 0; $i < 1000; $i++) {
* $fields["field:$i"] = "value:$i";
* }
*
* $redis->hmset('big-hash', $fields);
*
* $it = null;
*
* do {
* // Scan the hash but limit it to fields that match '*:1?3'
* $fields = $redis->hscan('big-hash', $it, '*:1?3');
*
* foreach ($fields as $field => $value) {
* echo "[$field] => $value\n";
* }
* } while ($it != 0);
*/
public function hscan(string $key, ?int &$iterator, ?string $pattern = null, int $count = 0): Redis|array|bool;
/**
* Increment a key's value, optionally by a specifc amount.
*
* @see https://redis.io/commands/incr
* @see https://redis.io/commands/incrby
*
* @param string $key The key to increment
* @param int $by An optional amount to increment by.
*
* @return Redis|int|false The new value of the key after incremented.
*
* @example $redis->incr('mycounter');
* @example $redis->incr('mycounter', 10);
*/
public function incr(string $key, int $by = 1): Redis|int|false;
/**
* Increment a key by a specific integer value
*
* @see https://redis.io/commands/incrby
*
* @param string $key The key to increment.
* @param int $value The amount to increment.
*
* @example
* $redis->set('primes', 2);
* $redis->incrby('primes', 1);
* $redis->incrby('primes', 2);
* $redis->incrby('primes', 2);
* $redis->incrby('primes', 4);
*/
public function incrBy(string $key, int $value): Redis|int|false;
/**
* Increment a numeric key by a floating point value.
*
* @param string $key The key to increment
* @param floag $value How much to increment (or decrement) the value.
*
* @return Redis|float|false The new value of the key or false if the key didn't contain a string.
*
* @example
* $redis->incrbyfloat('tau', 3.1415926);
* $redis->incrbyfloat('tau', 3.1415926);
*/
public function incrByFloat(string $key, float $value): Redis|float|false;
/**
* Retrieve information about the connected redis-server. If no arguments are passed to
* this function, redis will return every info field. Alternatively you may pass a specific
* section you want returned (e.g. 'server', or 'memory') to receive only information pertaining
* to that section.
*
* If connected to Redis server >= 7.0.0 you may pass multiple optional sections.
*
* @see https://redis.io/commands/info/
*
* @param string $sections Optional section(s) you wish Redis server to return.
*
* @return Redis|array|false
*/
public function info(string ...$sections): Redis|array|false;
/**
* Check if we are currently connected to a Redis instance.
*
* @return bool True if we are, false if not
*/
public function isConnected(): bool;
/** @return Redis|array|false */
public function keys(string $pattern);
/**
* @param mixed $elements
* @return Redis|int|false
*/
public function lInsert(string $key, string $pos, mixed $pivot, mixed $value);
/**
* Retrieve the lenght of a list.
*
* @param string $key The list
*
* @return Redis|int|false The number of elements in the list or false on failure.
*/
public function lLen(string $key): Redis|int|false;
/**
* Move an element from one list into another.
*
* @param string $src The source list.
* @param string $dst The destination list
* @param string $wherefrom Where in the source list to retrieve the element. This can be either
* - `Redis::LEFT`, or `Redis::RIGHT`.
* @param string $whereto Where in the destination list to put the element. This can be either
* - `Redis::LEFT`, or `Redis::RIGHT`.
* @return Redis|string|false The element removed from the source list.
*
* @example
* $redis->rPush('numbers', 'one', 'two', 'three');
* $redis->lMove('numbers', 'odds', Redis::LEFT, Redis::LEFT);
*/
public function lMove(string $src, string $dst, string $wherefrom, string $whereto): Redis|string|false;
/**
* Move an element from one list to another, blocking up to a timeout until an element is available.
*
* @param string $src The source list
* @param string $dst The destination list
* @param string $wherefrom Where in the source list to extract the element.
* - `Redis::LEFT`, or `Redis::RIGHT`.
* @param string $whereto Where in the destination list to put the element.
* - `Redis::LEFT`, or `Redis::RIGHT`.
* @param float $timeout How long to block for an element.
*
* @return Redis|string|false;
*
* @example
* @redis->lPush('numbers', 'one');
* @redis->blmove('numbers', 'odds', Redis::LEFT, Redis::LEFT 1.0);
* // This call will block, if no additional elements are in 'numbers'
* @redis->blmove('numbers', 'odds', Redis::LEFT, Redis::LEFT, 1.0);
*/
public function blmove(string $src, string $dst, string $wherefrom, string $whereto, float $timeout): Redis|string|false;
/**
* Pop one or more elements off a list.
*
* @param string $key The list to pop from.
* @param int $count Optional number of elements to remove. By default one element is popped.
* @return Redis|null|bool|int|array Will return the element(s) popped from the list or false/NULL
* if none was removed.
*
* @see https://redis.io/commands/lpop
*
* @example $redis->lpop('mylist');
* @example $redis->lpop('mylist', 4);
*/
public function lPop(string $key, int $count = 0): Redis|bool|string|array;
/**
* Retrieve the index of an element in a list.
*
* @param string $key The list to query.
* @param mixed $value The value to search for.
* @param array $options Options to configure how the command operates
*
* $options = [
* # How many matches to return. By default a single match is returned.
* # If count is set to zero, it means unlimited.
* 'COUNT' =>
*
* # Specify which match you want returned. `RANK` 1 means "the first match"
* # 2 means the second, and so on. If passed as a negative number the
* # RANK is computed right to left, so a `RANK` of -1 means "the last match".
* 'RANK' =>
*
* # This argument allows you to limit how many elements Redis will search before
* # returning. This is useful to prevent Redis searching very long lists while
* # blocking the client.
* 'MAXLEN =>
* ];
*
*
* @return Redis|null|bool|int|array Returns one or more of the matching indexes, or null/false if none were found.
*/
public function lPos(string $key, mixed $value, ?array $options = null): Redis|null|bool|int|array;
/**
* Prepend one or more elements to a list.
*
* @param string $key The list to prepend.
* @param mixed $elements One or more elements to prepend.
*
* @return Redis|int The new length of the list after prepending.
*
* @see https://redis.io/commands/lpush
*
* @example $redis->lPush('mylist', 'cat', 'bear', 'aligator');
*/
public function lPush(string $key, mixed ...$elements): Redis|int|false;
/**
* Append one or more elements to a list.
*
* @param string $key The list to append to.
* @param mixed $elements one or more elements to append.
*
* @return Redis|int|false The new length of the list
*
* @see https://redis.io/commands/rpush
*
* @example $redis->rPush('mylist', 'xray', 'yankee', 'zebra');
*/
public function rPush(string $key, mixed ...$elements): Redis|int|false;
/**
* Prepend an element to a list but only if the list exists
*
* @param string $key The key to prepend to.
* @param mixed $value The value to prepend.
*
* @return Redis|int|false The new length of the list.
*
*/
public function lPushx(string $key, mixed $value): Redis|int|false;
/**
* Append an element to a list but only if the list exists
*
* @param string $key The key to prepend to.
* @param mixed $value The value to prepend.
*
* @return Redis|int|false The new length of the list.
*
*/
public function rPushx(string $key, mixed $value): Redis|int|false;
/**
* Set a list element at an index to a specific value.
*
* @param string $key The list to modify.
* @param int $index The position of the element to change.
* @param mixed $value The new value.
*
* @return Redis|bool True if the list was modified.
*
* @see https://redis.io/commands/lset
*/
public function lSet(string $key, int $index, mixed $value): Redis|bool;
/**
* Retrieve the last time Redis' database was persisted to disk.
*
* @return int The unix timestamp of the last save time
*
* @see https://redis.io/commands/lastsave
*/
public function lastSave(): int;
/**
* Get the element of a list by its index.
*
* @param string $key The key to query
* @param int $index The index to check.
* @return mixed The index or NULL/false if the element was not found.
*/
public function lindex(string $key, int $index): mixed;
/**
* Retrieve elements from a list.
*
* @param string $key The list to query.
* @param int $start The beginning index to retrieve. This number can be negative
* meaning start from the end of the list.
* @param int $end The end index to retrieve. This can also be negative to start
* from the end of the list.
*
* @return Redis|array|false The range of elements between the indexes.
*
* @example $redis->lrange('mylist', 0, -1); // the whole list
* @example $redis->lrange('mylist', -2, -1); // the last two elements in the list.
*/
public function lrange(string $key, int $start , int $end): Redis|array|false;
/**
* Remove one or more matching elements from a list.
*
* @param string $key The list to truncate.
* @param mixed $value The value to remove.
* @param int $count How many elements matching the value to remove.
*
* @return Redis|int|false The number of elements removed.
*
* @see https://redis.io/commands/lrem
*/
public function lrem(string $key, mixed $value, int $count = 0): Redis|int|false;
/**
* Trim a list to a subrange of elements.
*
* @param string $key The list to trim
* @param int $start The starting index to keep
* @param int $end The ending index to keep.
*
* @return Redis|bool true if the list was trimmed.
*
* @example $redis->ltrim('mylist', 0, 3); // Keep the first four elements
*/
public function ltrim(string $key, int $start , int $end): Redis|bool;
/**
* Get one ore more string keys.
*
* @param array $keys The keys to retrieve
* @return Redis|array an array of keys with their values.
*
* @example $redis->mget(['key1', 'key2']);
*/
public function mget(array $keys): Redis|array;
public function migrate(string $host, int $port, string|array $key, int $dstdb, int $timeout,
bool $copy = false, bool $replace = false,
#[\SensitiveParameter] mixed $credentials = null): Redis|bool;
/**
* Move a key to a different database on the same redis instance.
*
* @param string $key The key to move
* @return Redis|bool True if the key was moved
*/
public function move(string $key, int $index): Redis|bool;
/**
* Set one ore more string keys.
*
* @param array $key_values An array with keys and their values.
* @return Redis|bool True if the keys could be set.
*
* @see https://redis.io/commands/mset
*
* @example $redis->mSet(['foo' => 'bar', 'baz' => 'bop']);
*/
public function mset(array $key_values): Redis|bool;
/**
* Set one ore more string keys but only if none of the key exist.
*
* @param array $key_values An array of keys with their values.
*
* @return Redis|bool True if the keys were set and false if not.
*
* @see https://redis.io/commands/msetnx
*
* @example $redis->msetnx(['foo' => 'bar', 'baz' => 'bop']);
*/
public function msetnx(array $key_values): Redis|bool;
/**
* Begin a transaction.
*
* @param int $value The type of transaction to start. This can either be `Redis::MULTI` or
* `Redis::PIPELINE'.
*
* @return Redis|bool True if the transaction could be started.
*
* @see https://redis.io/commands/multi
*
* @example
* $redis->multi();
* $redis->set('foo', 'bar');
* $redis->get('foo');
* $redis->exec();
*/
public function multi(int $value = Redis::MULTI): bool|Redis;
public function object(string $subcommand, string $key): Redis|int|string|false;
/**
* @deprecated
* @alias Redis::connect
*/
public function open(string $host, int $port = 6379, float $timeout = 0, ?string $persistent_id = null, int $retry_interval = 0, float $read_timeout = 0, ?array $context = null): bool;
public function pconnect(string $host, int $port = 6379, float $timeout = 0, ?string $persistent_id = null, int $retry_interval = 0, float $read_timeout = 0, ?array $context = null): bool;
/**
* Remove the expiration from a key.
*
* @param string $key The key to operate against.
*
* @return Redis|bool True if a timeout was removed and false if it was not or the key didn't exist.
*/
public function persist(string $key): Redis|bool;
/**
* Sets an expiration in milliseconds on a given key. If connected to Redis >= 7.0.0
* you can pass an optional mode argument that modifies how the command will execute.
*
* @see Redis::expire() for a description of the mode argument.
*
* @param string $key The key to set an expiration on.
* @param int $timeout The number of milliseconds after which key will be automatically deleted.
* @param string|null $mode A two character modifier that changes how the
* command works.
*
* @return Redis|bool True if an expiry was set on the key, and false otherwise.
*/
public function pexpire(string $key, int $timeout, ?string $mode = null): bool;
/**
* Set a key's expiration to a specific Unix Timestamp in milliseconds. If connected to
* Redis >= 7.0.0 you can pass an optional 'mode' argument.
*
* @see Redis::expire() For a description of the mode argument.
*
* @param string $key The key to set an expiration on.
* @param int $timestamp The unix timestamp to expire at.
* @param string|null $mode A two character modifier that changes how the
* command works.
*
* @return Redis|bool True if an expiration was set on the key, false otherwise.
*/
public function pexpireAt(string $key, int $timestamp, ?string $mode = null): Redis|bool;
/**
* Add one or more elements to a Redis HyperLogLog key
*
* @see https://redis.io/commands/pfadd
*
* @param string $key The key in question.
*
* @param array $elements One or more elements to add.
*
* @return Redis|int Returns 1 if the set was altered, and zero if not.
*/
public function pfadd(string $key, array $elements): Redis|int;
/**
* Retrieve the cardinality of a Redis HyperLogLog key.
*
* @see https://redis.io/commands/pfcount
*
* @param string $key_or_keys Either one key or an array of keys
*
* @return Redis|int The estimated cardinality of the set.
*/
public function pfcount(array|string $key_or_keys): Redis|int|false;
/**
* Merge one or more source HyperLogLog sets into a destination set.
*
* @see https://redis.io/commands/pfmerge
*
* @param string $dst The destination key.
* @param array $srckeys One or more source keys.
*
* @return Redis|bool Always returns true.
*/
public function pfmerge(string $dst, array $srckeys): Redis|bool;
/**
* PING the redis server with an optional string argument.
*
* @see https://redis.io/commands/ping
*
* @param string $message An optional string message that Redis will reply with, if passed.
*
* @return Redis|string|false If passed no message, this command will simply return `true`.
* If a message is passed, it will return the message.
*
* @example $redis->ping();
* @example $redis->ping('beep boop');
*/
public function ping(?string $message = null): Redis|string|bool;
/**
* Enter into pipeline mode.
*
* Pipeline mode is the highest performance way to send many commands to Redis
* as they are aggregated into one stream of commands and then all sent at once
* when the user calls Redis::exec().
*
* NOTE: That this is shorthand for Redis::multi(Redis::PIPELINE)
*
* @return Redis The redis object is returned, to facilitate method chaining.
*
* @example
* $redis->pipeline()
* ->set('foo', 'bar')
* ->del('mylist')
* ->rpush('mylist', 'a', 'b', 'c')
* ->exec();
*/
public function pipeline(): bool|Redis;
/**
* @deprecated
* @alias Redis::pconnect
*/
public function popen(string $host, int $port = 6379, float $timeout = 0, ?string $persistent_id = null, int $retry_interval = 0, float $read_timeout = 0, ?array $context = null): bool;
/**
* Set a key with an expiration time in milliseconds
*
* @param string $key The key to set
* @param int $expire The TTL to set, in milliseconds.
* @param mixed $value The value to set the key to.
*
* @return Redis|bool True if the key could be set.
*
* @example $redis->psetex('mykey', 1000, 'myval');
*/
public function psetex(string $key, int $expire, mixed $value): Redis|bool;
/**
* Subscribe to one or more glob-style patterns
*
* @param array $patterns One or more patterns to subscribe to.
* @param callable $cb A callback with the following prototype:
*
*
* function ($redis, $channel, $message) { }
*
*
* @see https://redis.io/commands/psubscribe
*
* @return bool True if we were subscribed.
*/
public function psubscribe(array $patterns, callable $cb): bool;
/**
* Get a keys time to live in milliseconds.
*
* @param string $key The key to check.
*
* @return Redis|int|false The key's TTL or one of two special values if it has none.
*
* -1 - The key has no TTL.
* -2 - The key did not exist.
*
*
* @see https://redis.io/commands/pttl
*
* @example $redis->pttl('ttl-key');
*/
public function pttl(string $key): Redis|int|false;
/**
* Publish a message to a pubsub channel
*
* @see https://redis.io/commands/publish
*
* @param string $channel The channel to publish to.
* @param string $message The message itself.
*
* @return Redis|int The number of subscribed clients to the given channel.
*/
public function publish(string $channel, string $message): Redis|int|false;
public function pubsub(string $command, mixed $arg = null): mixed;
/**
* Unsubscribe from one or more channels by pattern
*
* @see https://redis.io/commands/punsubscribe
* @see https://redis.io/commands/subscribe
* @see Redis::subscribe()
*
* @param array $patterns One or more glob-style patterns of channel names.
*
* @return Redis|array|bool The array of subscribed patterns or false on failure.
*/
public function punsubscribe(array $patterns): Redis|array|bool;
/**
* Pop one or more elements from the end of a list.
*
* @param string $key A redis LIST key name.
* @param int $count The maximum number of elements to pop at once.
* NOTE: The `count` argument requires Redis >= 6.2.0
*
* @return Redis|array|string|bool One ore more popped elements or false if all were empty.
*
* @see https://redis.io/commands/rpop
*
* @example $redis->rPop('mylist');
* @example $redis->rPop('mylist', 4);
*/
public function rPop(string $key, int $count = 0): Redis|array|string|bool;
/**
* Return a random key from the current database
*
* @see https://redis.io/commands/randomkey
*
* @return Redis|string|false A random key name or false if no keys exist
*
*/
public function randomKey(): Redis|string|false;
/**
* Execute any arbitrary Redis command by name.
*
* @param string $command The command to execute
* @param mixed $args One or more arguments to pass to the command.
*
* @return mixed Can return any number of things depending on command executed.
*
* @example $redis->rawCommand('del', 'mystring', 'mylist');
* @example $redis->rawCommand('set', 'mystring', 'myvalue');
* @example $redis->rawCommand('rpush', 'mylist', 'one', 'two', 'three');
*/
public function rawcommand(string $command, mixed ...$args): mixed;
/**
* Unconditionally rename a key from $old_name to $new_name
*
* @see https://redis.io/commands/rename
*
* @param string $old_name The original name of the key
* @param string $new_name The new name for the key
*
* @return Redis|bool True if the key was renamed or false if not.
*/
public function rename(string $old_name, string $new_name): Redis|bool;
/**
* Renames $key_src to $key_dst but only if newkey does not exist.
*
* @see https://redis.io/commands/renamenx
*
* @param string $key_src The source key name
* @param string $key_dst The destination key name.
*
* @return Redis|bool True if the key was renamed, false if not.
*
* @example
* $redis->set('src', 'src_key');
* $redis->set('existing-dst', 'i_exist');
*
* $redis->renamenx('src', 'dst');
* $redis->renamenx('dst', 'existing-dst');
*/
public function renameNx(string $key_src, string $key_dst): Redis|bool;
/**
* Reset the state of the connection.
*
* @return Redis|bool Should always return true unless there is an error.
*/
public function reset(): Redis|bool;
/**
* Restore a key by the binary payload generated by the DUMP command.
*
* @param string $key The name of the key you wish to create.
* @param int $ttl What Redis should set the key's TTL (in milliseconds) to once it is created.
* Zero means no TTL at all.
* @param string $value The serialized binary value of the string (generated by DUMP).
* @param array $options An array of additional options that modifies how the command operates.
*
*
* $options = [
* 'ABSTTL' # If this is present, the `$ttl` provided by the user should
* # be an absolute timestamp, in milliseconds()
*
* 'REPLACE' # This flag instructs Redis to store the key even if a key with
* # that name already exists.
*
* 'IDLETIME' => int # Tells Redis to set the keys internal 'idletime' value to a
* # specific number (see the Redis command OBJECT for more info).
* 'FREQ' => int # Tells Redis to set the keys internal 'FREQ' value to a specific
* # number (this relates to Redis' LFU eviction algorithm).
* ];
*
*
* @return Redis|bool True if the key was stored, false if not.
*
* @see https://redis.io/commands/restore
* @see https://redis.io/commands/dump
* @see Redis::dump()
*
* @example
* $redis->sAdd('captains', 'Janeway', 'Picard', 'Sisko', 'Kirk', 'Archer');
* $serialized = $redis->dump('captains');
*
* $redis->restore('captains-backup', 0, $serialized);
*/
public function restore(string $key, int $ttl, string $value, ?array $options = null): Redis|bool;
/**
* Query whether the connected instance is a primary or replica
*
* @return mixed Will return an array with the role of the connected instance unless there is
* an error.
*/
public function role(): mixed;
/**
* Atomically pop an element off the end of a Redis LIST and push it to the beginning of
* another.
*
* @param string $srckey The source key to pop from.
* @param string $dstkey The destination key to push to.
*
* @return Redis|string|false The popped element or false if the source key was empty.
*
* @see https://redis.io/commands/rpoplpush
*
* @example
* $redis->pipeline()
* ->del('list1', 'list2')
* ->rpush('list1', 'list1-1', 'list1-2')
* ->rpush('list2', 'list2-1', 'list2-2')
* ->exec();
*
* $redis->rpoplpush('list2', 'list1');
*/
public function rpoplpush(string $srckey, string $dstkey): Redis|string|false;
/**
* Add one or more values to a Redis SET key.
*
* @param string $key The key name
* @param mixed $member A value to add to the set.
* @param mixed $other_members One or more additional values to add
*
* @return Redis|int|false The number of values added to the set.
*
* @see https://redis.io/commands/sadd
*
* @example
* $redis->del('myset');
*
* $redis->sadd('myset', 'foo', 'bar', 'baz');
* $redis->sadd('myset', 'foo', 'new');
*/
public function sAdd(string $key, mixed $value, mixed ...$other_values): Redis|int|false;
/**
* Add one ore more values to a Redis SET key. This is an alternative to Redis::sadd() but
* instead of being variadic, takes a single array of values.
*
* @see https://redis.io/commands/sadd
* @see Redis::sadd()
*
* @param string $key The set to add values to.
* @param array $values One or more members to add to the set.
* @return Redis|int|false The number of members added to the set.
*
* @example
* $redis->del('myset');
*
* $redis->sAddArray('myset', ['foo', 'bar', 'baz']);
* $redis->sAddArray('myset', ['foo', 'new']);
*/
public function sAddArray(string $key, array $values): int;
/**
* Given one or more Redis SETS, this command returns all of the members from the first
* set that are not in any subsequent set.
*
* @param string $key The first set
* @param string $other_keys One or more additional sets
*
* @return Redis|array|false Returns the elements from keys 2..N that don't exist in the
* first sorted set, or false on failure.
*
* @see https://redis.io/commands/sdiff
*
* @example
* $redis->pipeline()
* ->del('set1', 'set2', 'set3')
* ->sadd('set1', 'apple', 'banana', 'carrot', 'date')
* ->sadd('set2', 'carrot')
* ->sadd('set3', 'apple', 'carrot', 'eggplant')
* ->exec();
*
* $redis->sdiff('set1', 'set2', 'set3');
*/
public function sDiff(string $key, string ...$other_keys): Redis|array|false;
/**
* This method performs the same operation as SDIFF except it stores the resulting diff
* values in a specified destination key.
*
* @see https://redis.io/commands/sdiffstore
* @see Redis::sdiff()
*
* @param string $dst The key where to store the result
* @param string $key The first key to perform the DIFF on
* @param string $other_keys One or more additional keys.
*
* @return Redis|int|false The number of values stored in the destination set or false on failure.
*/
public function sDiffStore(string $dst, string $key, string ...$other_keys): Redis|int|false;
/**
* Given one or more Redis SET keys, this command will return all of the elements that are
* in every one.
*
* @see https://redis.io/commands/sinter
*
* @param string $key The first SET key to intersect.
* @param string $other_keys One or more Redis SET keys.
*
* @example
* $redis->pipeline()
* ->del('alice_likes', 'bob_likes', 'bill_likes')
* ->sadd('alice_likes', 'asparagus', 'broccoli', 'carrot', 'potato')
* ->sadd('bob_likes', 'asparagus', 'carrot', 'potato')
* ->sadd('bill_likes', 'broccoli', 'potato')
* ->exec();
*
* var_dump($redis->sinter('alice_likes', 'bob_likes', 'bill_likes'));
*
*/
public function sInter(array|string $key, string ...$other_keys): Redis|array|false;
/**
* Compute the intersection of one or more sets and return the cardinality of the result.
*
* @param array $keys One or more set key names.
* @param int $limit A maximum cardinality to return. This is useful to put an upper bound
* on the amount of work Redis will do.
*
* @return Redis|int|false The
*
* @see https://redis.io/commands/sintercard
*
* @example
* $redis->sAdd('set1', 'apple', 'pear', 'banana', 'carrot');
* $redis->sAdd('set2', 'apple', 'banana');
* $redis->sAdd('set3', 'pear', 'banana');
*
* $redis->sInterCard(['set1', 'set2', 'set3']);
* ?>
*
*/
public function sintercard(array $keys, int $limit = -1): Redis|int|false;
/**
* Perform the intersection of one or more Redis SETs, storing the result in a destination
* key, rather than returning them.
*
* @param array|string $key_or_keys Either a string key, or an array of keys (with at least two
* elements, consisting of the destination key name and one
* or more source keys names.
* @param string $other_keys If the first argument was a string, subsequent arguments should
* be source key names.
*
* @return Redis|int|false The number of values stored in the destination key or false on failure.
*
* @see https://redis.io/commands/sinterstore
* @see Redis::sinter()
*
* @example $redis->sInterStore(['dst', 'src1', 'src2', 'src3']);
* @example $redis->sInterStore('dst', 'src1', 'src'2', 'src3');
* ?>
*
*/
public function sInterStore(array|string $key, string ...$other_keys): Redis|int|false;
/**
* Retrieve every member from a set key.
*
* @param string $key The set name.
*
* @return Redis|array|false Every element in the set or false on failure.
*
* @see https://redis.io/commands/smembers
*
* @example
* $redis->sAdd('tng-crew', ...['Picard', 'Riker', 'Data', 'Worf', 'La Forge', 'Troi', 'Crusher', 'Broccoli']);
* $redis->sMembers('tng-crew');
*/
public function sMembers(string $key): Redis|array|false;
/**
* Check if one or more values are members of a set.
*
* @see https://redis.io/commands/smismember
* @see https://redis.io/commands/smember
* @see Redis::smember()
*
* @param string $key The set to query.
* @param string $member The first value to test if exists in the set.
* @param string $other_members Any number of additional values to check.
*
* @return Redis|array|false An array of integers representing whether each passed value
* was a member of the set.
*
* @example
* $redis->sAdd('ds9-crew', ...["Sisko", "Kira", "Dax", "Worf", "Bashir", "O'Brien"]);
* $members = $redis->sMIsMember('ds9-crew', ...['Sisko', 'Picard', 'Data', 'Worf']);
*/
public function sMisMember(string $key, string $member, string ...$other_members): Redis|array|false;
/**
* Pop a member from one set and push it onto another. This command will create the
* destination set if it does not currently exist.
*
* @see https://redis.io/commands/smove
*
* @param string $src The source set.
* @param string $dst The destination set.
* @param mixed $value The member you wish to move.
*
* @return Redis|bool True if the member was moved, and false if it wasn't in the set.
*
* @example
* $redis->sAdd('numbers', 'zero', 'one', 'two', 'three', 'four');
* $redis->sMove('numbers', 'evens', 'zero');
* $redis->sMove('numbers', 'evens', 'two');
* $redis->sMove('numbers', 'evens', 'four');
*/
public function sMove(string $src, string $dst, mixed $value): Redis|bool;
/**
* Remove one or more elements from a set.
*
* @see https://redis.io/commands/spop
*
* @param string $key The set in question.
* @param int $count An optional number of members to pop. This defaults to
* removing one element.
*
* @example
* $redis->del('numbers', 'evens');
* $redis->sAdd('numbers', 'zero', 'one', 'two', 'three', 'four');
* $redis->sPop('numbers');
*/
public function sPop(string $key, int $count = 0): Redis|string|array|false;
/**
* Retrieve one or more random members of a set.
*
* @param string $key The set to query.
* @param int $count An optional count of members to return.
*
* If this value is positive, Redis will return *up to* the requested
* number but with unique elements that will never repeat. This means
* you may recieve fewer then `$count` replies.
*
* If the number is negative, Redis will return the exact number requested
* but the result may contain duplicate elements.
*
* @return Redis|array|string|false One or more random members or false on failure.
*
* @see https://redis.io/commands/srandmember
*
* @example $redis->sRandMember('myset');
* @example $redis->sRandMember('myset', 10);
* @example $redis->sRandMember('myset', -10);
*/
public function sRandMember(string $key, int $count = 0): Redis|string|array|false;
/**
* Returns the union of one or more Redis SET keys.
*
* @see https://redis.io/commands/sunion
*
* @param string $key The first SET to do a union with
* @param string $other_keys One or more subsequent keys
*
* @return Redis|array|false The union of the one or more input sets or false on failure.
*
* @example $redis->sunion('set1', 'set2');
*/
public function sUnion(string $key, string ...$other_keys): Redis|array|false;
/**
* Perform a union of one or more Redis SET keys and store the result in a new set
*
* @see https://redis.io/commands/sunionstore
* @see Redis::sunion()
*
* @param string $dst The destination key
* @param string $key The first source key
* @param string $other_keys One or more additional source keys
*
* @return Redis|int|false The number of elements stored in the destination SET or
* false on failure.
*/
public function sUnionStore(string $dst, string $key, string ...$other_keys): Redis|int|false;
/**
* Persist the Redis database to disk. This command will block the server until the save is
* completed. For a nonblocking alternative, see Redis::bgsave().
*
* @see https://redis.io/commands/save
* @see Redis::bgsave()
*
* @return Redis|bool Returns true unless an error occurs.
*/
public function save(): Redis|bool;
/**
* Incrementally scan the Redis keyspace, with optional pattern and type matching.
*
* A note about Redis::SCAN_NORETRY and Redis::SCAN_RETRY.
*
* For convenience, PhpRedis can retry SCAN commands itself when Redis returns an empty array of
* keys with a nonzero iterator. This can happen when matching against a pattern that very few
* keys match inside a key space with a great many keys. The following example demonstrates how
* to use Redis::scan() with the option disabled and enabled.
*
* @param int $iterator The cursor returned by Redis for every subsequent call to SCAN. On
* the initial invocation of the call, it should be initialized by the
* caller to NULL. Each time SCAN is invoked, the iterator will be
* updated to a new number, until finally Redis will set the value to
* zero, indicating that the scan is complete.
*
* @param string $pattern An optional glob-style pattern for matching key names. If passed as
* NULL, it is the equivalent of sending '*' (match every key).
*
* @param int $count A hint to redis that tells it how many keys to return in a single
* call to SCAN. The larger the number, the longer Redis may block
* clients while iterating the key space.
*
* @param string $type An optional argument to specify which key types to scan (e.g.
* 'STRING', 'LIST', 'SET')
*
* @return array|false An array of keys, or false if no keys were returned for this
* invocation of scan. Note that it is possible for Redis to return
* zero keys before having scanned the entire key space, so the caller
* should instead continue to SCAN until the iterator reference is
* returned to zero.
*
* @see https://redis.io/commands/scan
* @see Redis::setOption()
*
* @example
* $redis = new Redis(['host' => 'localhost']);
*
* $redis->setOption(Redis::OPT_SCAN, Redis::SCAN_NORETRY);
*
* $it = null;
*
* do {
* $keys = $redis->scan($it, '*zorg*');
* foreach ($keys as $key) {
* echo "KEY: $key\n";
* }
* } while ($it != 0);
*
* $redis->setOption(Redis::OPT_SCAN, Redis::SCAN_RETRY);
*
* $it = null;
*
* // When Redis::SCAN_RETRY is enabled, we can use simpler logic, as we will never receive an
* // empty array of keys when the iterator is nonzero.
* while ($keys = $redis->scan($it, '*zorg*')) {
* foreach ($keys as $key) {
* echo "KEY: $key\n";
* }
* }
*/
public function scan(?int &$iterator, ?string $pattern = null, int $count = 0, ?string $type = null): array|false;
/**
* Retrieve the number of members in a Redis set.
*
* @param string $key The set to get the cardinality of.
*
* @return Redis|int|false The cardinality of the set or false on failure.
*
* @see https://redis.io/commands/scard
*
* @example $redis->scard('set');
*
*/
public function scard(string $key): Redis|int|false;
/**
* An administrative command used to interact with LUA scripts stored on the server.
*
* @see https://redis.io/commands/script
*
* @param string $command The script suboperation to execute.
* @param mixed $args One ore more additional argument
*
* @return mixed This command returns various things depending on the specific operation executed.
*
* @example $redis->script('load', 'return 1');
* @example $redis->script('exists', sha1('return 1'));
*/
public function script(string $command, mixed ...$args): mixed;
/**
* Select a specific Redis database.
*
* @param int $db The database to select. Note that by default Redis has 16 databases (0-15).
*
* @return Redis|bool true on success and false on failure
*
* @see https://redis.io/commands/select
*
* @example $redis->select(1);
*/
public function select(int $db): Redis|bool;
/**
* Create or set a Redis STRING key to a value.
*
* @param string $key The key name to set.
* @param mixed $value The value to set the key to.
* @param array|int $options Either an array with options for how to perform the set or an
* integer with an expiration. If an expiration is set PhpRedis
* will actually send the `SETEX` command.
*
* OPTION DESCRIPTION
* ------------ --------------------------------------------------------------
* ['EX' => 60] expire 60 seconds.
* ['PX' => 6000] expire in 6000 milliseconds.
* ['EXAT' => time() + 10] expire in 10 seconds.
* ['PXAT' => time()*1000 + 1000] expire in 1 second.
* ['KEEPTTL' => true] Redis will not update the key's current TTL.
* ['XX'] Only set the key if it already exists.
* ['NX'] Only set the key if it doesn't exist.
* ['GET'] Instead of returning `+OK` return the previous value of the
* key or NULL if the key didn't exist.
*
* @return Redis|string|bool True if the key was set or false on failure.
*
* @see https://redis.io/commands/set
* @see https://redis.io/commands/setex
*
* @example $redis->set('key', 'value');
* @example $redis->set('key', 'expires_in_60_seconds', 60);
*/
public function set(string $key, mixed $value, mixed $options = null): Redis|string|bool;
/**
* Set a specific bit in a Redis string to zero or one
*
* @see https://redis.io/commands/setbit
*
* @param string $key The Redis STRING key to modify
* @param bool $value Whether to set the bit to zero or one.
*
* @return Redis|int|false The original value of the bit or false on failure.
*
* @example
* $redis->set('foo', 'bar');
* $redis->setbit('foo', 7, 1);
*/
public function setBit(string $key, int $idx, bool $value): Redis|int|false;
/**
* Update or append to a Redis string at a specific starting index
*
* @see https://redis.io/commands/setrange
*
* @param string $key The key to update
* @param int $index Where to insert the provided value
* @param string $value The value to copy into the string.
*
* @return Redis|int|false The new length of the string or false on failure
*
* @example
* $redis->set('message', 'Hello World');
* $redis->setRange('message', 6, 'Redis');
*/
public function setRange(string $key, int $index, string $value): Redis|int|false;
/**
* Set a configurable option on the Redis object.
*
* Following are a list of options you can set:
*
* | OPTION | TYPE | DESCRIPTION |
* | --------------- | ---- | ----------- |
* | OPT_MAX_RETRIES | int | The maximum number of times Redis will attempt to reconnect if it gets disconnected, before throwing an exception. |
* | OPT_SCAN | enum | Redis::OPT_SCAN_RETRY, or Redis::OPT_SCAN_NORETRY. Whether PhpRedis should automatically SCAN again when zero keys but a nonzero iterator are returned. |
* | OPT_SERIALIZER | enum | Set the automatic data serializer.
`Redis::SERIALIZER_NONE`
`Redis::SERIALIZER_PHP`
`Redis::SERIALIZER_IGBINARY`
`Redis::SERIALIZER_MSGPACK`, `Redis::SERIALIZER_JSON`|
* | OPT_PREFIX | string | A string PhpRedis will use to prefix every key we read or write. |
* | OPT_READ_TIMEOUT | float | How long PhpRedis will block for a response from Redis before throwing a 'read error on connection' exception. |
* | OPT_TCP_KEEPALIVE | bool | Set or disable TCP_KEEPALIVE on the connection. |
* | OPT_COMPRESSION | enum | Set the compression algorithm
`Redis::COMPRESSION_NONE`
`Redis::COMPRESSION_LZF`
`Redis::COMPRESSION_LZ4`
`Redis::COMPRESSION_ZSTD` |
* | OPT_REPLY_LITERAL | bool | If set to true, PhpRedis will return the literal string Redis returns for LINE replies (e.g. '+OK'), rather than `true`. |
* | OPT_COMPRESSION_LEVEL | int | Set a specific compression level if Redis is compressing data. |
* | OPT_NULL_MULTIBULK_AS_NULL | bool | Causes PhpRedis to return `NULL` rather than `false` for NULL MULTIBULK replies |
* | OPT_BACKOFF_ALGORITHM | enum | The exponential backoff strategy to use. |
* | OPT_BACKOFF_BASE | int | The minimum delay between retries when backing off. |
* | OPT_BACKOFF_CAP | int | The maximum delay between replies when backing off. |
*
* @see Redis::getOption()
* @see Redis::__construct() for details about backoff strategies.
*
* @param int $option The option constant.
* @param mixed $value The option value.
*
* @return bool true if the setting was updated, false if not.
*
*/
public function setOption(int $option, mixed $value): bool;
/**
* Set a Redis STRING key with a specific expiration in seconds.
*
* @param string $key The name of the key to set.
* @param int $expire The key's expiration in seconds.
* @param mixed $value The value to set the key.
*
* @return Redis|bool True on success or false on failure.
*
* @example $redis->setex('60s-ttl', 60, 'some-value');
*/
public function setex(string $key, int $expire, mixed $value);
/**
* Set a key to a value, but only if that key does not already exist.
*
* @see https://redis.io/commands/setnx
*
* @param string $key The key name to set.
* @param mixed $value What to set the key to.
*
* @return Redis|bool Returns true if the key was set and false otherwise.
*
* @example $redis->setnx('existing-key', 'existing-value');
* @example $redis->setnx('new-key', 'new-value');
*/
public function setnx(string $key, mixed $value): Redis|bool;
/**
* Check whether a given value is the member of a Redis SET.
*
* @param string $key The redis set to check.
* @param mixed $value The value to test.
*
* @return Redis|bool True if the member exists and false if not.
*
* @example $redis->sismember('myset', 'mem1', 'mem2');
*/
public function sismember(string $key, mixed $value): Redis|bool;
/**
* Turn a redis instance into a replica of another or promote a replica
* to a primary.
*
* This method and the corresponding command in Redis has been marked deprecated
* and users should instead use Redis::replicaof() if connecting to redis-server
* >= 5.0.0.
*
* @deprecated
*
* @see https://redis.io/commands/slaveof
* @see https://redis.io/commands/replicaof
* @see Redis::replicaof()
*/
public function slaveof(?string $host = null, int $port = 6379): Redis|bool;
/**
* Used to turn a Redis instance into a replica of another, or to remove
* replica status promoting the instance to a primary.
*
* @see https://redis.io/commands/replicaof
* @see https://redis.io/commands/slaveof
* @see Redis::slaveof()
*
* @param string $host The host of the primary to start replicating.
* @param string $port The port of the primary to start replicating.
*
* @return Redis|bool Success if we were successfully able to start replicating a primary or
* were able to promote teh replicat to a primary.
*
* @example
* $redis = new Redis(['host' => 'localhost']);
*
* // Attempt to become a replica of a Redis instance at 127.0.0.1:9999
* $redis->replicaof('127.0.0.1', 9999);
*
* // When passed no arguments, PhpRedis will deliver the command `REPLICAOF NO ONE`
* // attempting to promote the instance to a primary.
* $redis->replicaof();
*/
public function replicaof(?string $host = null, int $port = 6379): Redis|bool;
/**
* Update one or more keys last modified metadata.
*
* @see https://redis.io/commands/touch/
*
* @param array|string $key Either the first key or if passed as the only argument
* an array of keys.
* @param string $more_keys One or more keys to send to the command.
*
* @return Redis|int|false This command returns the number of keys that exist and
* had their last modified time reset
*/
public function touch(array|string $key_or_array, string ...$more_keys): Redis|int|false;
/**
* Interact with Redis' slowlog functionality in various ways, depending
* on the value of 'operation'.
*
* @category administration
*
* @param string $operation The operation you wish to perform. This can
* be one of the following values:
* 'GET' - Retrieve the Redis slowlog as an array.
* 'LEN' - Retrieve the length of the slowlog.
* 'RESET' - Remove all slowlog entries.
* @param int $length This optional argument can be passed when operation
* is 'get' and will specify how many elements to retrieve.
* If omitted Redis will send up to a default number of
* entries, which is configurable.
*
* Note: With Redis >= 7.0.0 you can send -1 to mean "all".
*
* @return mixed
*
* @see https://redis.io/commands/slowlog/
*
* @example $redis->slowlog('get', -1); // Retrieve all slowlog entries.
* @example $redis->slowlog('len'); // Retrieve slowlog length.
* @example $redis->slowlog('reset'); // Reset the slowlog.
*/
public function slowlog(string $operation, int $length = 0): mixed;
/**
* Sort the contents of a Redis key in various ways.
*
* @see https://redis.io/commands/sort/
*
* @param string $key The key you wish to sort
* @param array $options Various options controlling how you would like the
* data sorted. See blow for a detailed description
* of this options array.
*
* @return mixed This command can either return an array with the sorted data
* or the number of elements placed in a destination set when
* using the STORE option.
*
* @example
* $options = [
* 'SORT' => 'ASC'|| 'DESC' // Sort in descending or descending order.
* 'ALPHA' => true || false // Whether to sort alphanumerically.
* 'LIMIT' => [0, 10] // Return a subset of the data at offset, count
* 'BY' => 'weight_*' // For each element in the key, read data from the
* external key weight_* and sort based on that value.
* 'GET' => 'weight_*' // For each element in the source key, retrieve the
* data from key weight_* and return that in the result
* rather than the source keys' element. This can
* be used in combination with 'BY'
* ];
*/
public function sort(string $key, ?array $options = null): mixed;
/**
* This is simply a read-only variant of the sort command
*
* @see Redis::sort()
*/
public function sort_ro(string $key, ?array $options = null): mixed;
/**
* @deprecated
*/
public function sortAsc(string $key, ?string $pattern = null, mixed $get = null, int $offset = -1, int $count = -1, ?string $store = null): array;
/**
* @deprecated
*/
public function sortAscAlpha(string $key, ?string $pattern = null, mixed $get = null, int $offset = -1, int $count = -1, ?string $store = null): array;
/**
* @deprecated
*/
public function sortDesc(string $key, ?string $pattern = null, mixed $get = null, int $offset = -1, int $count = -1, ?string $store = null): array;
/**
* @deprecated
*/
public function sortDescAlpha(string $key, ?string $pattern = null, mixed $get = null, int $offset = -1, int $count = -1, ?string $store = null): array;
/**
* Remove one or more values from a Redis SET key.
*
* @see https://redis.io/commands/srem
*
* @param string $key The Redis SET key in question.
* @param mixed $value The first value to remove.
* @param mixed $more_values One or more additional values to remove.
*
* @return Redis|int|false The number of values removed from the set or false on failure.
*
* @example $redis->sRem('set1', 'mem1', 'mem2', 'not-in-set');
*/
public function srem(string $key, mixed $value, mixed ...$other_values): Redis|int|false;
/**
* Scan the members of a redis SET key.
*
* @see https://redis.io/commands/sscan
* @see https://redis.io/commands/scan
* @see Redis::setOption()
*
* @param string $key The Redis SET key in question.
* @param int $iterator A reference to an iterator which should be initialized to NULL that
* PhpRedis will update with the value returned from Redis after each
* subsequent call to SSCAN. Once this cursor is zero you know all
* members have been traversed.
* @param string $pattern An optional glob style pattern to match against, so Redis only
* returns the subset of members matching this pattern.
* @param int $count A hint to Redis as to how many members it should scan in one command
* before returning members for that iteration.
*
* @example
* $redis->del('myset');
* for ($i = 0; $i < 10000; $i++) {
* $redis->sAdd('myset', "member:$i");
* }
* $redis->sadd('myset', 'foofoo');
*
* $redis->setOption(Redis::OPT_SCAN, Redis::SCAN_NORETRY);
*
* $scanned = 0;
* $it = null;
*
* // Without Redis::SCAN_RETRY we may receive empty results and
* // a nonzero iterator.
* do {
* // Scan members containing '5'
* $members = $redis->sscan('myset', $it, '*5*');
* foreach ($members as $member) {
* echo "NORETRY: $member\n";
* $scanned++;
* }
* } while ($it != 0);
* echo "TOTAL: $scanned\n";
*
* $redis->setOption(Redis::OPT_SCAN, Redis::SCAN_RETRY);
*
* $scanned = 0;
* $it = null;
*
* // With Redis::SCAN_RETRY PhpRedis will never return an empty array
* // when the cursor is non-zero
* while (($members = $redis->sscan('myset', $it, '*5*'))) {
* foreach ($members as $member) {
* echo "RETRY: $member\n";
* $scanned++;
* }
* }
*/
public function sscan(string $key, ?int &$iterator, ?string $pattern = null, int $count = 0): array|false;
/**
* Subscribes the client to the specified shard channels.
*
* @param array $channels One or more channel names.
* @param callable $cb The callback PhpRedis will invoke when we receive a message
* from one of the subscribed channels.
*
* @return bool True on success, false on faiilure. Note that this command will block the
* client in a subscribe loop, waiting for messages to arrive.
*
* @see https://redis.io/commands/ssubscribe
*
* @example
* $redis = new Redis(['host' => 'localhost']);
*
* $redis->ssubscribe(['channel-1', 'channel-2'], function ($redis, $channel, $message) {
* echo "[$channel]: $message\n";
*
* // Unsubscribe from the message channel when we read 'quit'
* if ($message == 'quit') {
* echo "Unsubscribing from '$channel'\n";
* $redis->sunsubscribe([$channel]);
* }
* });
*
* // Once we read 'quit' from both channel-1 and channel-2 the subscribe loop will be
* // broken and this command will execute.
* echo "Subscribe loop ended\n";
*/
public function ssubscribe(array $channels, callable $cb): bool;
/**
* Retrieve the length of a Redis STRING key.
*
* @param string $key The key we want the length of.
*
* @return Redis|int|false The length of the string key if it exists, zero if it does not, and
* false on failure.
*
* @see https://redis.io/commands/strlen
*
* @example $redis->strlen('mykey');
*/
public function strlen(string $key): Redis|int|false;
/**
* Subscribe to one or more Redis pubsub channels.
*
* @param array $channels One or more channel names.
* @param callable $cb The callback PhpRedis will invoke when we receive a message
* from one of the subscribed channels.
*
* @return bool True on success, false on faiilure. Note that this command will block the
* client in a subscribe loop, waiting for messages to arrive.
*
* @see https://redis.io/commands/subscribe
*
* @example
* $redis = new Redis(['host' => 'localhost']);
*
* $redis->subscribe(['channel-1', 'channel-2'], function ($redis, $channel, $message) {
* echo "[$channel]: $message\n";
*
* // Unsubscribe from the message channel when we read 'quit'
* if ($message == 'quit') {
* echo "Unsubscribing from '$channel'\n";
* $redis->unsubscribe([$channel]);
* }
* });
*
* // Once we read 'quit' from both channel-1 and channel-2 the subscribe loop will be
* // broken and this command will execute.
* echo "Subscribe loop ended\n";
*/
public function subscribe(array $channels, callable $cb): bool;
/**
* Unsubscribes the client from the given shard channels,
* or from all of them if none is given.
*
* @param array $channels One or more channels to unsubscribe from.
* @return Redis|array|bool The array of unsubscribed channels.
*
* @see https://redis.io/commands/sunsubscribe
* @see Redis::ssubscribe()
*
* @example
* $redis->ssubscribe(['channel-1', 'channel-2'], function ($redis, $channel, $message) {
* if ($message == 'quit') {
* echo "$channel => 'quit' detected, unsubscribing!\n";
* $redis->sunsubscribe([$channel]);
* } else {
* echo "$channel => $message\n";
* }
* });
*
* echo "We've unsubscribed from both channels, exiting\n";
*/
public function sunsubscribe(array $channels): Redis|array|bool;
/**
* Atomically swap two Redis databases so that all of the keys in the source database will
* now be in the destination database and vice-versa.
*
* Note: This command simply swaps Redis' internal pointer to the database and is therefore
* very fast, regardless of the size of the underlying databases.
*
* @param int $src The source database number
* @param int $dst The destination database number
*
* @return Redis|bool Success if the databases could be swapped and false on failure.
*
* @see https://redis.io/commands/swapdb
* @see Redis::del()
*
* @example
* $redis->select(0);
* $redis->set('db0-key', 'db0-value');
* $redis->swapdb(0, 1);
* $redis->get('db0-key');
*/
public function swapdb(int $src, int $dst): Redis|bool;
/**
* Retrieve the server time from the connected Redis instance.
*
* @see https://redis.io/commands/time
*
* @return A two element array consisting of a Unix Timestamp and the number of microseconds
* elapsed since the second.
*
* @example $redis->time();
*/
public function time(): Redis|array;
/**
* Get the amount of time a Redis key has before it will expire, in seconds.
*
* @param string $key The Key we want the TTL for.
* @return Redis|int|false (a) The number of seconds until the key expires, or -1 if the key has
* no expiration, and -2 if the key does not exist. In the event of an
* error, this command will return false.
*
* @see https://redis.io/commands/ttl
*
* @example $redis->ttl('mykey');
*/
public function ttl(string $key): Redis|int|false;
/**
* Get the type of a given Redis key.
*
* @see https://redis.io/commands/type
*
* @param string $key The key to check
* @return Redis|int|false The Redis type constant or false on failure.
*
* The Redis class defines several type constants that correspond with Redis key types.
*
* Redis::REDIS_NOT_FOUND
* Redis::REDIS_STRING
* Redis::REDIS_SET
* Redis::REDIS_LIST
* Redis::REDIS_ZSET
* Redis::REDIS_HASH
* Redis::REDIS_STREAM
*
* @example
* foreach ($redis->keys('*') as $key) {
* echo "$key => " . $redis->type($key) . "\n";
* }
*/
public function type(string $key): Redis|int|false;
/**
* Delete one or more keys from the Redis database. Unlike this operation, the actual
* deletion is asynchronous, meaning it is safe to delete large keys without fear of
* Redis blocking for a long period of time.
*
* @param array|string $key_or_keys Either an array with one or more keys or a string with
* the first key to delete.
* @param string $other_keys If the first argument passed to this method was a string
* you may pass any number of additional key names.
*
* @return Redis|int|false The number of keys deleted or false on failure.
*
* @see https://redis.io/commands/unlink
* @see https://redis.io/commands/del
* @see Redis::del()
*
* @example $redis->unlink('key1', 'key2', 'key3');
* @example $redis->unlink(['key1', 'key2', 'key3']);
*/
public function unlink(array|string $key, string ...$other_keys): Redis|int|false;
/**
* Unsubscribe from one or more subscribed channels.
*
* @param array $channels One or more channels to unsubscribe from.
* @return Redis|array|bool The array of unsubscribed channels.
*
* @see https://redis.io/commands/unsubscribe
* @see Redis::subscribe()
*
* @example
* $redis->subscribe(['channel-1', 'channel-2'], function ($redis, $channel, $message) {
* if ($message == 'quit') {
* echo "$channel => 'quit' detected, unsubscribing!\n";
* $redis->unsubscribe([$channel]);
* } else {
* echo "$channel => $message\n";
* }
* });
*
* echo "We've unsubscribed from both channels, exiting\n";
*/
public function unsubscribe(array $channels): Redis|array|bool;
/**
* Remove any previously WATCH'ed keys in a transaction.
*
* @see https://redis.io/commands/unwatch
* @see https://redis.io/commands/unwatch
* @see Redis::watch()
*
* @return True on success and false on failure.
*/
public function unwatch(): Redis|bool;
/**
* Watch one or more keys for conditional execution of a transaction.
*
* @param array|string $key_or_keys Either an array with one or more key names, or a string key name
* @param string $other_keys If the first argument was passed as a string, any number of additional
* string key names may be passed variadically.
* @return Redis|bool
*
*
* @see https://redis.io/commands/watch
* @see https://redis.io/commands/unwatch
*
* @example
* $redis1 = new Redis(['host' => 'localhost']);
* $redis2 = new Redis(['host' => 'localhost']);
*
* // Start watching 'incr-key'
* $redis1->watch('incr-key');
*
* // Retrieve its value.
* $val = $redis1->get('incr-key');
*
* // A second client modifies 'incr-key' after we read it.
* $redis2->set('incr-key', 0);
*
* // Because another client changed the value of 'incr-key' after we read it, this
* // is no longer a proper increment operation, but because we are `WATCH`ing the
* // key, this transaction will fail and we can try again.
* //
* // If were to comment out the above `$redis2->set('incr-key', 0)` line the
* // transaction would succeed.
* $redis1->multi();
* $redis1->set('incr-key', $val + 1);
* $res = $redis1->exec();
*
* // bool(false)
* var_dump($res);
*/
public function watch(array|string $key, string ...$other_keys): Redis|bool;
/**
* Block the client up to the provided timeout until a certain number of replicas have confirmed
* recieving them.
*
* @see https://redis.io/commands/wait
*
* @param int $numreplicas The number of replicas we want to confirm write operaions
* @param int $timeout How long to wait (zero meaning forever).
*
* @return Redis|int|false The number of replicas that have confirmed or false on failure.
*
*/
public function wait(int $numreplicas, int $timeout): int|false;
/**
* Acknowledge one ore more messages that are pending (have been consumed using XREADGROUP but
* not yet acknowledged by XACK.)
*
* @param string $key The stream to query.
* @param string $group The consumer group to use.
* @param array $ids An array of stream entry IDs.
*
* @return int|false The number of acknowledged messages
*
* @see https://redis.io/commands/xack
* @see https://redis.io/commands/xreadgroup
* @see Redis::xack()
*
* @example
* $redis->xAdd('ships', '*', ['name' => 'Enterprise']);
* $redis->xAdd('ships', '*', ['name' => 'Defiant']);
*
* $redis->xGroup('CREATE', 'ships', 'Federation', '0-0');
*
* // Consume a single message with the consumer group 'Federation'
* $ship = $redis->xReadGroup('Federation', 'Picard', ['ships' => '>'], 1);
*
* /* Retrieve the ID of the message we read.
* assert(isset($ship['ships']));
* $id = key($ship['ships']);
*
* // The message we just read is now pending.
* $res = $redis->xPending('ships', 'Federation'));
* var_dump($res);
*
* // We can tell Redis we were able to process the message by using XACK
* $res = $redis->xAck('ships', 'Federation', [$id]);
* assert($res === 1);
*
* // The message should no longer be pending.
* $res = $redis->xPending('ships', 'Federation');
* var_dump($res);
*/
public function xack(string $key, string $group, array $ids): int|false;
/**
* Append a message to a stream.
*
* @param string $key The stream name.
* @param string $id The ID for the message we want to add. This can be the special value '*'
* which means Redis will generate the ID that appends the message to the
* end of the stream. It can also be a value in the form -* which will
* generate an ID that appends to the end ot entries with the same value
* (if any exist).
* @param int $maxlen If specified Redis will append the new message but trim any number of the
* oldest messages in the stream until the length is <= $maxlen.
* @param bool $approx Used in conjunction with `$maxlen`, this flag tells Redis to trim the stream
* but in a more efficient way, meaning the trimming may not be exactly to
* `$maxlen` values.
* @param bool $nomkstream If passed as `TRUE`, the stream must exist for Redis to append the message.
*
* @see https://redis.io/commands/xadd
*
* @example $redis->xAdd('ds9-season-1', '1-1', ['title' => 'Emissary Part 1']);
* @example $redis->xAdd('ds9-season-1', '1-2', ['title' => 'A Man Alone']);
*/
public function xadd(string $key, string $id, array $values, int $maxlen = 0, bool $approx = false, bool $nomkstream = false): Redis|string|false;
/**
* This command allows a consumer to claim pending messages that have been idle for a specified period of time.
* Its purpose is to provide a mechanism for picking up messages that may have had a failed consumer.
*
* @see https://redis.io/commands/xautoclaim
* @see https://redis.io/commands/xclaim
* @see https://redis.io/docs/data-types/streams-tutorial/
*
* @param string $key The stream to check.
* @param string $group The consumer group to query.
* @param string $consumer Which consumer to check.
* @param int $min_idle The minimum time in milliseconds for the message to have been pending.
* @param string $start The minimum message id to check.
* @param int $count An optional limit on how many messages are returned.
* @param bool $justid If the client only wants message IDs and not all of their data.
*
* @return Redis|array|bool An array of pending IDs or false if there are none, or on failure.
*
* @example
* $redis->xGroup('CREATE', 'ships', 'combatants', '0-0', true);
*
* $redis->xAdd('ships', '1424-74205', ['name' => 'Defiant']);
*
* // Consume the ['name' => 'Defiant'] message
* $msgs = $redis->xReadGroup('combatants', "Jem'Hadar", ['ships' => '>'], 1);
*
* // The "Jem'Hadar" consumer has the message presently
* $pending = $redis->xPending('ships', 'combatants');
* var_dump($pending);
*
* // Asssume control of the pending message with a different consumer.
* $res = $redis->xAutoClaim('ships', 'combatants', 'Sisko', 0, '0-0');
*
* // Now the 'Sisko' consumer owns the message
* $pending = $redis->xPending('ships', 'combatants');
* var_dump($pending);
*/
public function xautoclaim(string $key, string $group, string $consumer, int $min_idle, string $start, int $count = -1, bool $justid = false): Redis|bool|array;
/**
* This method allows a consumer to take ownership of pending stream entries, by ID. Another
* command that does much the same thing but does not require passing specific IDs is `Redis::xAutoClaim`.
*
* @see https://redis.io/commands/xclaim
* @see https://redis.io/commands/xautoclaim.
*
* @param string $key The stream we wish to claim messages for.
* @param string $group Our consumer group.
* @param string $consumer Our consumer.
* @param int $min_idle_time The minimum idle-time in milliseconds a message must have for ownership to be transferred.
* @param array $options An options array that modifies how the command operates.
*
*
* # Following is an options array describing every option you can pass. Note that
* # 'IDLE', and 'TIME' are mutually exclusive.
* $options = [
* 'IDLE' => 3 # Set the idle time of the message to a 3. By default
* # the idle time is set to zero.
* 'TIME' => 1000*time() # Same as IDLE except it takes a unix timestamp in
* # milliseconds.
* 'RETRYCOUNT' => 0 # Set the retry counter to zero. By default XCLAIM
* # doesn't modify the counter.
* 'FORCE' # Creates the pending message entry even if IDs are
* # not already
* # in the PEL with another client.
* 'JUSTID' # Return only an array of IDs rather than the messages
* # themselves.
* ];
*
*
* @return Redis|array|bool An array of claimed messags or false on failure.
*
* @example
* $redis->xGroup('CREATE', 'ships', 'combatants', '0-0', true);
*
* $redis->xAdd('ships', '1424-74205', ['name' => 'Defiant']);
*
* // Consume the ['name' => 'Defiant'] message
* $msgs = $redis->xReadGroup('combatants', "Jem'Hadar", ['ships' => '>'], 1);
*
* // The "Jem'Hadar" consumer has the message presently
* $pending = $redis->xPending('ships', 'combatants');
* var_dump($pending);
*
* assert($pending && isset($pending[1]));
*
* // Claim the message by ID.
* $claimed = $redis->xClaim('ships', 'combatants', 'Sisko', 0, [$pending[1]], ['JUSTID']);
* var_dump($claimed);
*
* // Now the 'Sisko' consumer owns the message
* $pending = $redis->xPending('ships', 'combatants');
* var_dump($pending);
*/
public function xclaim(string $key, string $group, string $consumer, int $min_idle, array $ids, array $options): Redis|array|bool;
/**
* Remove one or more specific IDs from a stream.
*
* @param string $key The stream to modify.
* @param array $ids One or more message IDs to remove.
*
* @return Redis|int|false The number of messages removed or false on failure.
*
* @example $redis->xDel('stream', ['1-1', '2-1', '3-1']);
*/
public function xdel(string $key, array $ids): Redis|int|false;
/**
* XGROUP
*
* Perform various operation on consumer groups for a particular Redis STREAM. What the command does
* is primarily based on which operation is passed.
*
* @see https://redis.io/commands/xgroup/
*
* @param string $operation The subcommand you intend to execute. Valid options are as follows
* 'HELP' - Redis will return information about the command
* Requires: none
* 'CREATE' - Create a consumer group.
* Requires: Key, group, consumer.
* 'SETID' - Set the ID of an existing consumer group for the stream.
* Requires: Key, group, id.
* 'CREATECONSUMER' - Create a new consumer group for the stream. You must
* also pass key, group, and the consumer name you wish to
* create.
* Requires: Key, group, consumer.
* 'DELCONSUMER' - Delete a consumer from group attached to the stream.
* Requires: Key, group, consumer.
* 'DESTROY' - Delete a consumer group from a stream.
* Requires: Key, group.
* @param string $key The STREAM we're operating on.
* @param string $group The consumer group we want to create/modify/delete.
* @param string $id_or_consumer The STREAM id (e.g. '$') or consumer group. See the operation section
* for information about which to send.
* @param bool $mkstream This flag may be sent in combination with the 'CREATE' operation, and
* cause Redis to also create the STREAM if it doesn't currently exist.
*
* @param bool $entriesread Allows you to set Redis' 'entries-read' STREAM value. This argument is
* only relevant to the 'CREATE' and 'SETID' operations.
* Note: Requires Redis >= 7.0.0.
*
* @return mixed This command return various results depending on the operation performed.
*/
public function xgroup(string $operation, ?string $key = null, ?string $group = null, ?string $id_or_consumer = null,
bool $mkstream = false, int $entries_read = -2): mixed;
/**
* Retrieve information about a stream key.
*
* @param string $operation The specific info operation to perform.
* @param string $arg1 The first argument (depends on operation)
* @param string $arg2 The second argument
* @param int $count The COUNT argument to `XINFO STREAM`
*
* @return mixed This command can return different things depending on the operation being called.
*
* @see https://redis.io/commands/xinfo
*
* @example $redis->xInfo('CONSUMERS', 'stream');
* @example $redis->xInfo('GROUPS', 'stream');
* @example $redis->xInfo('STREAM', 'stream');
*/
public function xinfo(string $operation, ?string $arg1 = null, ?string $arg2 = null, int $count = -1): mixed;
/**
* Get the number of messages in a Redis STREAM key.
*
* @param string $key The Stream to check.
*
* @return Redis|int|false The number of messages or false on failure.
*
* @see https://redis.io/commands/xlen
*
* @example $redis->xLen('stream');
*/
public function xlen(string $key): Redis|int|false;
/**
* Interact with stream messages that have been consumed by a consumer group but not yet
* acknowledged with XACK.
*
* @see https://redis.io/commands/xpending
* @see https://redis.io/commands/xreadgroup
*
* @param string $key The stream to inspect.
* @param string $group The user group we want to see pending messages from.
* @param string $start The minimum ID to consider.
* @param string $string The maximum ID to consider.
* @param string $count Optional maximum number of messages to return.
* @param string $consumer If provided, limit the returned messages to a specific consumer.
*
* @return Redis|array|false The pending messages belonging to the stream or false on failure.
*
*/
public function xpending(string $key, string $group, ?string $start = null, ?string $end = null, int $count = -1, ?string $consumer = null): Redis|array|false;
/**
* Get a range of entries from a STREAM key.
*
* @param string $key The stream key name to list.
* @param string $start The minimum ID to return.
* @param string $end The maximum ID to return.
* @param int $count An optional maximum number of entries to return.
*
* @return Redis|array|bool The entries in the stream within the requested range or false on failure.
*
* @see https://redis.io/commands/xrange
*
* @example $redis->xRange('stream', '0-1', '0-2');
* @example $redis->xRange('stream', '-', '+');
*/
public function xrange(string $key, string $start, string $end, int $count = -1): Redis|array|bool;
/**
* Consume one or more unconsumed elements in one or more streams.
*
* @param array $streams An associative array with stream name keys and minimum id values.
* @param int $count An optional limit to how many entries are returnd *per stream*
* @param int $block An optional maximum number of milliseconds to block the caller if no
* data is available on any of the provided streams.
*
* @return Redis|array|bool An array of read elements or false if there aren't any.
*
* @see https://redis.io/commands/xread
*
* @example
* $redis->xAdd('s03', '3-1', ['title' => 'The Search, Part I']);
* $redis->xAdd('s03', '3-2', ['title' => 'The Search, Part II']);
* $redis->xAdd('s03', '3-3', ['title' => 'The House Of Quark']);
* $redis->xAdd('s04', '4-1', ['title' => 'The Way of the Warrior']);
* $redis->xAdd('s04', '4-3', ['title' => 'The Visitor']);
* $redis->xAdd('s04', '4-4', ['title' => 'Hippocratic Oath']);
*
* $redis->xRead(['s03' => '3-2', 's04' => '4-1']);
*/
public function xread(array $streams, int $count = -1, int $block = -1): Redis|array|bool;
/**
* Read one or more messages using a consumer group.
*
* @param string $group The consumer group to use.
* @param string $consumer The consumer to use.
* @param array $streams An array of stream names and message IDs
* @param int $count Optional maximum number of messages to return
* @param int $block How long to block if there are no messages available.
*
* @return Redis|array|bool Zero or more unread messages or false on failure.
*
* @see https://redis.io/commands/xreadgroup
*
* @example
* $redis->xGroup('CREATE', 'episodes', 'ds9', '0-0', true);
*
* $redis->xAdd('episodes', '1-1', ['title' => 'Emissary: Part 1']);
* $redis->xAdd('episodes', '1-2', ['title' => 'A Man Alone']);
*
* $messages = $redis->xReadGroup('ds9', 'sisko', ['episodes' => '>']);
*
* // After having read the two messages, add another
* $redis->xAdd('episodes', '1-3', ['title' => 'Emissary: Part 2']);
*
* // Acknowledge the first two read messages
* foreach ($messages as $stream => $stream_messages) {
* $ids = array_keys($stream_messages);
* $redis->xAck('stream', 'ds9', $ids);
* }
*
* // We can now pick up where we left off, and will only get the final message
* $msgs = $redis->xReadGroup('ds9', 'sisko', ['episodes' => '>']);
*/
public function xreadgroup(string $group, string $consumer, array $streams, int $count = 1, int $block = 1): Redis|array|bool;
/**
* Get a range of entries from a STREAM ke in reverse cronological order.
*
* @param string $key The stream key to query.
* @param string $end The maximum message ID to include.
* @param string $start The minimum message ID to include.
* @param int $count An optional maximum number of messages to include.
*
* @return Redis|array|bool The entries within the requested range, from newest to oldest.
*
* @see https://redis.io/commands/xrevrange
* @see https://redis.io/commands/xrange
*
* @example $redis->xRevRange('stream', '0-2', '0-1');
* @example $redis->xRevRange('stream', '+', '-');
*/
public function xrevrange(string $key, string $end, string $start, int $count = -1): Redis|array|bool;
/**
* Truncate a STREAM key in various ways.
*
* @param string $key The STREAM key to trim.
* @param string $threshold This can either be a maximum length, or a minimum id.
* MAXLEN - An integer describing the maximum desired length of the stream after the command.
* MINID - An ID that will become the new minimum ID in the stream, as Redis will trim all
* messages older than this ID.
* @param bool $approx Whether redis is allowed to do an approximate trimming of the stream. This is
* more efficient for Redis given how streams are stored internally.
* @param bool $minid When set to `true`, users should pass a minimum ID to the `$threshold` argument.
* @param int $limit An optional upper bound on how many entries to trim during the command.
*
* @return Redis|int|false The number of entries deleted from the stream.
*
* @see https://redis.io/commands/xtrim
*
* @example $redis->xTrim('stream', 3);
* @example $redis->xTrim('stream', '2-1', false, true);
*/
public function xtrim(string $key, string $threshold, bool $approx = false, bool $minid = false, int $limit = -1): Redis|int|false;
/**
* Add one or more elements and scores to a Redis sorted set.
*
* @param string $key The sorted set in question.
* @param array|float $score_or_options Either the score for the first element, or an array of options.
*
* $options = [
* 'NX', # Only update elements that already exist
* 'NX', # Only add new elements but don't update existing ones.
*
* 'LT' # Only update existing elements if the new score is
* # less than the existing one.
* 'GT' # Only update existing elements if the new score is
* # greater than the existing one.
*
* 'CH' # Instead of returning the number of elements added,
* # Redis will return the number Of elements that were
* # changed in the operation.
*
* 'INCR' # Instead of setting each element to the provide score,
* # increment the element by the
* # provided score, much like ZINCRBY. When this option
* # is passed, you may only send a single score and member.
* ];
*
* Note: 'GX', 'LT', and 'NX' cannot be passed together, and PhpRedis
* will send whichever one is last in the options array.
*
* @param mixed $more_scores_and_mems A variadic number of additional scores and members.
*
* @return Redis|int|false The return value varies depending on the options passed.
*
* Following is information about the options that may be passed as the second argument:
*
* @see https://redis.io/commands/zadd
*
* @example $redis->zadd('zs', 1, 'first', 2, 'second', 3, 'third');
* @example $redis->zAdd('zs', ['XX'], 8, 'second', 99, 'new-element');
*/
public function zAdd(string $key, array|float $score_or_options, mixed ...$more_scores_and_mems): Redis|int|float|false;
/**
* Return the number of elements in a sorted set.
*
* @param string $key The sorted set to retreive cardinality from.
*
* @return Redis|int|false The number of elements in the set or false on failure
*
* @see https://redis.io/commands/zcard
*
* @example $redis->zCard('zs');
*/
public function zCard(string $key): Redis|int|false;
/**
* Count the number of members in a sorted set with scores inside a provided range.
*
* @param string $key The sorted set to check.
* @param string $min The minimum score to include in the count
* @param string $max The maximum score to include in the count
*
* NOTE: In addition to a floating point score you may pass the special values of '-inf' and
* '+inf' meaning negative and positive infinity, respectively.
*
* @see https://redis.io/commands/zcount
*
* @example $redis->zCount('fruit-rankings', '0', '+inf');
* @example $redis->zCount('fruit-rankings', 50, 60);
* @example $redis->zCount('fruit-rankings', '-inf', 0);
*/
public function zCount(string $key, string $start, string $end): Redis|int|false;
/**
* Create or increment the score of a member in a Redis sorted set
*
* @param string $key The sorted set in question.
* @param float $value How much to increment the score.
*
* @return Redis|float|false The new score of the member or false on failure.
*
* @see https://redis.io/commands/zincrby
*
* @example $redis->zIncrBy('zs', 5.0, 'bananas');
* @example $redis->zIncrBy('zs', 2.0, 'eggplants');
*/
public function zIncrBy(string $key, float $value, mixed $member): Redis|float|false;
/**
* Count the number of elements in a sorted set whos members fall within the provided
* lexographical range.
*
* @param string $key The sorted set to check.
* @param string $min The minimum matching lexographical string
* @param string $max The maximum matching lexographical string
*
* @return Redis|int|false The number of members that fall within the range or false on failure.
*
* @see https://redis.io/commands/zlexcount
*
* @example
* $redis->zAdd('captains', 0, 'Janeway', 0, 'Kirk', 0, 'Picard', 0, 'Sisko', 0, 'Archer');
* $redis->zLexCount('captains', '[A', '[S');
*/
public function zLexCount(string $key, string $min, string $max): Redis|int|false;
/**
* Retrieve the score of one or more members in a sorted set.
*
* @see https://redis.io/commands/zmscore
*
* @param string $key The sorted set
* @param mixed $member The first member to return the score from
* @param mixed $other_members One or more additional members to return the scores of.
*
* @return Redis|array|false An array of the scores of the requested elements.
*
* @example
* $redis->zAdd('zs', 0, 'zero', 1, 'one', 2, 'two', 3, 'three');
*
* $redis->zMScore('zs', 'zero', 'two');
* $redis->zMScore('zs', 'one', 'not-a-member');
*/
public function zMscore(string $key, mixed $member, mixed ...$other_members): Redis|array|false;
/**
* Pop one or more of the highest scoring elements from a sorted set.
*
* @param string $key The sorted set to pop elements from.
* @param int $count An optional count of elements to pop.
*
* @return Redis|array|false All of the popped elements with scores or false on fialure.
*
* @see https://redis.io/commands/zpopmax
*
* @example
* $redis->zAdd('zs', 0, 'zero', 1, 'one', 2, 'two', 3, 'three');
*
* $redis->zPopMax('zs');
* $redis->zPopMax('zs', 2);.
*/
public function zPopMax(string $key, ?int $count = null): Redis|array|false;
/**
* Pop one or more of the lowest scoring elements from a sorted set.
*
* @param string $key The sorted set to pop elements from.
* @param int $count An optional count of elements to pop.
*
* @return Redis|array|false The popped elements with their scores or false on failure.
*
* @see https://redis.io/commands/zpopmin
*
* @example
* $redis->zAdd('zs', 0, 'zero', 1, 'one', 2, 'two', 3, 'three');
*
* $redis->zPopMin('zs');
* $redis->zPopMin('zs', 2);
*/
public function zPopMin(string $key, ?int $count = null): Redis|array|false;
/**
* Retrieve a range of elements of a sorted set between a start and end point.
* How the command works in particular is greatly affected by the options that
* are passed in.
*
* @param string $key The sorted set in question.
* @param mixed $start The starting index we want to return.
* @param mixed $end The final index we want to return.
*
* @param array|bool|null $options This value may either be an array of options to pass to
* the command, or for historical purposes a boolean which
* controls just the 'WITHSCORES' option.
*
* $options = [
* 'WITHSCORES' => true, # Return both scores and members.
* 'LIMIT' => [10, 10], # Start at offset 10 and return 10 elements.
* 'REV' # Return the elements in reverse order
* 'BYSCORE', # Treat `start` and `end` as scores instead
* 'BYLEX' # Treat `start` and `end` as lexicographical values.
* ];
*
*
* Note: 'BYLEX' and 'BYSCORE' are mutually exclusive.
*
*
* @return Redis|array|false An array with matching elements or false on failure.
*
* @see https://redis.io/commands/zrange/
* @category zset
*
* @example $redis->zRange('zset', 0, -1);
* @example $redis->zRange('zset', '-inf', 'inf', ['byscore']);
*/
public function zRange(string $key, string|int $start, string|int $end, array|bool|null $options = null): Redis|array|false;
/**
* Retrieve a range of elements from a sorted set by legographical range.
*
* @param string $key The sorted set to retreive elements from
* @param string $min The minimum legographical value to return
* @param string $max The maximum legographical value to return
* @param int $offset An optional offset within the matching values to return
* @param int $count An optional count to limit the replies to (used in conjunction with offset)
*
* @return Redis|array|false An array of matching elements or false on failure.
*
* @see https://redis.io/commands/zrangebylex
*
* @example
* $redis = new Redis(['host' => 'localhost']);
* $redis->zAdd('captains', 0, 'Janeway', 0, 'Kirk', 0, 'Picard', 0, 'Sisko', 0, 'Archer');
*
* $redis->zRangeByLex('captains', '[A', '[S');
* $redis->zRangeByLex('captains', '[A', '[S', 2, 2);
*/
public function zRangeByLex(string $key, string $min, string $max, int $offset = -1, int $count = -1): Redis|array|false;
/**
* Retrieve a range of members from a sorted set by their score.
*
* @param string $key The sorted set to query.
* @param string $start The minimum score of elements that Redis should return.
* @param string $end The maximum score of elements that Redis should return.
* @param array $options Options that change how Redis will execute the command.
*
* OPTION TYPE MEANING
* 'WITHSCORES' bool Whether to also return scores.
* 'LIMIT' [offset, count] Limit the reply to a subset of elements.
*
* @return Redis|array|false The number of matching elements or false on failure.
*
* @see https://redis.io/commands/zrangebyscore
*
* @example $redis->zRangeByScore('zs', 20, 30, ['WITHSCORES' => true]);
* @example $redis->zRangeByScore('zs', 20, 30, ['WITHSCORES' => true, 'LIMIT' => [5, 5]]);
*/
public function zRangeByScore(string $key, string $start, string $end, array $options = []): Redis|array|false;
/**
* This command is similar to ZRANGE except that instead of returning the values directly
* it will store them in a destination key provided by the user
*
* @param string $dstkey The key to store the resulting element(s)
* @param string $srckey The source key with element(s) to retrieve
* @param string $start The starting index to store
* @param string $end The ending index to store
* @param array|bool|null $options Our options array that controls how the command will function.
*
* @return Redis|int|false The number of elements stored in $dstkey or false on failure.
*
* @see https://redis.io/commands/zrange/
* @see Redis::zRange
* @category zset
*
* See {@link Redis::zRange} for a full description of the possible options.
*/
public function zrangestore(string $dstkey, string $srckey, string $start, string $end,
array|bool|null $options = null): Redis|int|false;
/**
* Retrieve one or more random members from a Redis sorted set.
*
* @param string $key The sorted set to pull random members from.
* @param array $options One or more options that determine exactly how the command operates.
*
* OPTION TYPE MEANING
* 'COUNT' int The number of random members to return.
* 'WITHSCORES' bool Whether to return scores and members instead of
*
* @return Redis|string|array One ore more random elements.
*
* @see https://redis.io/commands/zrandmember
*
* @example $redis->zRandMember('zs', ['COUNT' => 2, 'WITHSCORES' => true]);
*/
public function zRandMember(string $key, ?array $options = null): Redis|string|array;
/**
* Get the rank of a member of a sorted set, by score.
*
* @param string $key The sorted set to check.
* @param mixed $memeber The member to test.
*
* @return Redis|int|false The rank of the requested member.
* @see https://redis.io/commands/zrank
*
* @example $redis->zRank('zs', 'zero');
* @example $redis->zRank('zs', 'three');
*/
public function zRank(string $key, mixed $member): Redis|int|false;
/**
* Remove one or more members from a Redis sorted set.
*
* @param mixed $key The sorted set in question.
* @param mixed $member The first member to remove.
* @param mixed $other_members One or more members to remove passed in a variadic fashion.
*
* @return Redis|int|false The number of members that were actually removed or false on failure.
*
* @see https://redis.io/commands/zrem
*
* @example $redis->zRem('zs', 'mem:0', 'mem:1', 'mem:2', 'mem:6', 'mem:7', 'mem:8', 'mem:9');
*/
public function zRem(mixed $key, mixed $member, mixed ...$other_members): Redis|int|false;
/**
* Remove zero or more elements from a Redis sorted set by legographical range.
*
* @param string $key The sorted set to remove elements from.
* @param string $min The start of the lexographical range to remove.
* @param string $max The end of the lexographical range to remove
*
* @return Redis|int|false The number of elements removed from the set or false on failure.
*
* @see https://redis.io/commands/zremrangebylex
* @see Redis::zrangebylex()
*
* @example $redis->zRemRangeByLex('zs', '[a', '(b');
* @example $redis->zRemRangeByLex('zs', '(banana', '(eggplant');
*/
public function zRemRangeByLex(string $key, string $min, string $max): Redis|int|false;
/**
* Remove one or more members of a sorted set by their rank.
*
* @param string $key The sorted set where we wnat to remove members.
* @param int $start The rank when we want to start removing members
* @param int $end The rank we want to stop removing membersk.
*
* @return Redis|int|false The number of members removed from the set or false on failure.
*
* @see https://redis.io/commands/zremrangebyrank
*
* @example $redis->zRemRangeByRank('zs', 0, 3);
*/
public function zRemRangeByRank(string $key, int $start, int $end): Redis|int|false;
/**
* Remove one or more members of a sorted set by their score.
*
* @param string $key The sorted set where we wnat to remove members.
* @param int $start The lowest score to remove.
* @param int $end The highest score to remove.
*
* @return Redis|int|false The number of members removed from the set or false on failure.
*
* @see https://redis.io/commands/zremrangebyrank
*
* @example
* $redis->zAdd('zs', 2, 'two', 4, 'four', 6, 'six');
* $redis->zRemRangeByScore('zs', 2, 4);
*/
public function zRemRangeByScore(string $key, string $start, string $end): Redis|int|false;
/**
* List the members of a Redis sorted set in reverse order
*
* @param string $key The sorted set in question.
* @param int $start The index to start listing elements
* @param int $end The index to stop listing elements.
* @param mixed $withscores Whether or not Redis should also return each members score. See
* the example below demonstrating how it may be used.
*
* @return Redis|array|false The members (and possibly scores) of the matching elements or false
* on failure.
*
* @see https://redis.io/commands/zrevrange
*
* @example $redis->zRevRange('zs', 0, -1);
* @example $redis->zRevRange('zs', 2, 3);
* @example $redis->zRevRange('zs', 0, -1, true);
* @example $redis->zRevRange('zs', 0, -1, ['withscores' => true]);
*/
public function zRevRange(string $key, int $start, int $end, mixed $scores = null): Redis|array|false;
/**
* List members of a Redis sorted set within a legographical range, in reverse order.
*
* @param string $key The sorted set to list
* @param string $min The maximum legographical element to include in the result.
* @param string $min The minimum lexographical element to include in the result.
* @param string $offset An option offset within the matching elements to start at.
* @param string $count An optional count to limit the replies to.
*
* @return Redis|array|false The matching members or false on failure.
*
* @see https://redis.io/commands/zrevrangebylex
* @see Redis::zrangebylex()
*
* @example $redis->zRevRangeByLex('captains', '[Q', '[J');
* @example $redis->zRevRangeByLex('captains', '[Q', '[J', 1, 2);
*/
public function zRevRangeByLex(string $key, string $max, string $min, int $offset = -1, int $count = -1): Redis|array|false;
/**
* List elements from a Redis sorted set by score, highest to lowest
*
* @param string $key The sorted set to query.
* @param string $max The highest score to include in the results.
* @param string $min The lowest score to include in the results.
* @param array $options An options array that modifies how the command executes.
*
*
* $options = [
* 'WITHSCORES' => true|false # Whether or not to return scores
* 'LIMIT' => [offset, count] # Return a subset of the matching members
* ];
*
*
* NOTE: For legacy reason, you may also simply pass `true` for the
* options argument, to mean `WITHSCORES`.
*
* @return Redis|array|false The matching members in reverse order of score or false on failure.
*
* @see https://redis.io/commands/zrevrangebyscore
*
* @example
* $redis->zadd('oldest-people', 122.4493, 'Jeanne Calment', 119.2932, 'Kane Tanaka',
* 119.2658, 'Sarah Knauss', 118.7205, 'Lucile Randon',
* 117.7123, 'Nabi Tajima', 117.6301, 'Marie-Louise Meilleur',
* 117.5178, 'Violet Brown', 117.3753, 'Emma Morano',
* 117.2219, 'Chiyo Miyako', 117.0740, 'Misao Okawa');
*
* $redis->zRevRangeByScore('oldest-people', 122, 119);
* $redis->zRevRangeByScore('oldest-people', 'inf', 118);
* $redis->zRevRangeByScore('oldest-people', '117.5', '-inf', ['LIMIT' => [0, 1]]);
*/
public function zRevRangeByScore(string $key, string $max, string $min, array|bool $options = []): Redis|array|false;
/**
* Retrieve a member of a sorted set by reverse rank.
*
* @param string $key The sorted set to query.
* @param mixed $member The member to look up.
*
* @return Redis|int|false The reverse rank (the rank if counted high to low) of the member or
* false on failure.
* @see https://redis.io/commands/zrevrank
*
* @example
* $redis->zAdd('ds9-characters', 10, 'Sisko', 9, 'Garak', 8, 'Dax', 7, 'Odo');
*
* $redis->zrevrank('ds9-characters', 'Sisko');
* $redis->zrevrank('ds9-characters', 'Garak');
*/
public function zRevRank(string $key, mixed $member): Redis|int|false;
/**
* Get the score of a member of a sorted set.
*
* @param string $key The sorted set to query.
* @param mixed $member The member we wish to query.
*
* @return The score of the requested element or false if it is not found.
*
* @see https://redis.io/commands/zscore
*
* @example
* $redis->zAdd('telescopes', 11.9, 'LBT', 10.4, 'GTC', 10, 'HET');
* $redis->zScore('telescopes', 'LBT');
*/
public function zScore(string $key, mixed $member): Redis|float|false;
/**
* Given one or more sorted set key names, return every element that is in the first
* set but not any of the others.
*
* @param array $keys One ore more sorted sets.
* @param array $options An array which can contain ['WITHSCORES' => true] if you want Redis to
* return members and scores.
*
* @return Redis|array|false An array of members or false on failure.
*
* @see https://redis.io/commands/zdiff
*
* @example
* $redis->zAdd('primes', 1, 'one', 3, 'three', 5, 'five');
* $redis->zAdd('evens', 2, 'two', 4, 'four');
* $redis->zAdd('mod3', 3, 'three', 6, 'six');
*
* $redis->zDiff(['primes', 'evens', 'mod3']);
*/
public function zdiff(array $keys, ?array $options = null): Redis|array|false;
/**
* Store the difference of one or more sorted sets in a destination sorted set.
*
* See {@link Redis::zdiff} for a more detailed description of how the diff operation works.
*
* @param string $key The destination set name.
* @param array $keys One or more source key names
*
* @return Redis|int|false The number of elements stored in the destination set or false on
* failure.
*
* @see https://redis.io/commands/zdiff
* @see Redis::zdiff()
*/
public function zdiffstore(string $dst, array $keys): Redis|int|false;
/**
* Compute the intersection of one or more sorted sets and return the members
*
* @param array $keys One ore more sorted sets.
* @param array $weights An optional array of weights to be applied to each set when performing
* the intersection.
* @param array $options Options for how Redis should combine duplicate elements when performing the
* intersection. See Redis::zunion() for details.
*
* @return Redis|array|false All of the members that exist in every set.
*
* @see https://redis.io/commands/zinter
*
* @example
* $redis->zAdd('TNG', 2, 'Worf', 2.5, 'Data', 4.0, 'Picard');
* $redis->zAdd('DS9', 2.5, 'Worf', 3.0, 'Kira', 4.0, 'Sisko');
*
* $redis->zInter(['TNG', 'DS9']);
* $redis->zInter(['TNG', 'DS9'], NULL, ['withscores' => true]);
* $redis->zInter(['TNG', 'DS9'], NULL, ['withscores' => true, 'aggregate' => 'max']);
*/
public function zinter(array $keys, ?array $weights = null, ?array $options = null): Redis|array|false;
/**
* Similar to ZINTER but instead of returning the intersected values, this command returns the
* cardinality of the intersected set.
*
* @see https://redis.io/commands/zintercard
* @see https://redis.io/commands/zinter
* @see Redis::zinter()
*
* @param array $keys One ore more sorted set key names.
* @param int $limit An optional upper bound on the returned cardinality. If set to a value
* greater than zero, Redis will stop processing the intersection once the
* resulting cardinality reaches this limit.
*
* @return Redis|int|false The cardinality of the intersection or false on failure.
*
* @example
* $redis->zAdd('zs1', 1, 'one', 2, 'two', 3, 'three', 4, 'four');
* $redis->zAdd('zs2', 2, 'two', 4, 'four');
*
* $redis->zInterCard(['zs1', 'zs2']);
*/
public function zintercard(array $keys, int $limit = -1): Redis|int|false;
/**
* Compute the intersection of one ore more sorted sets storing the result in a new sorted set.
*
* @param string $dst The destination sorted set to store the intersected values.
* @param array $keys One ore more sorted set key names.
* @param array $weights An optional array of floats to weight each passed input set.
* @param string $aggregate An optional aggregation method to use.
*
* 'SUM' - Store sum of all intersected members (this is the default).
* 'MIN' - Store minimum value for each intersected member.
* 'MAX' - Store maximum value for each intersected member.
*
* @return Redis|int|false The total number of members writtern to the destination set or false on failure.
*
* @see https://redis.io/commands/zinterstore
* @see https://redis.io/commands/zinter
*
* @example
* $redis->zAdd('zs1', 3, 'apples', 2, 'pears');
* $redis->zAdd('zs2', 4, 'pears', 3, 'bananas');
* $redis->zAdd('zs3', 2, 'figs', 3, 'pears');
*
* $redis->zInterStore('fruit-sum', ['zs1', 'zs2', 'zs3']);
* $redis->zInterStore('fruit-max', ['zs1', 'zs2', 'zs3'], NULL, 'MAX');
*/
public function zinterstore(string $dst, array $keys, ?array $weights = null, ?string $aggregate = null): Redis|int|false;
/**
* Scan the members of a sorted set incrementally, using a cursor
*
* @param string $key The sorted set to scan.
* @param int $iterator A reference to an iterator that should be initialized to NULL initially, that
* will be updated after each subsequent call to ZSCAN. Once the iterator
* has returned to zero the scan is complete
* @param string $pattern An optional glob-style pattern that limits which members are returned during
* the scanning process.
* @param int $count A hint for Redis that tells it how many elements it should test before returning
* from the call. The higher the more work Redis may do in any one given call to
* ZSCAN potentially blocking for longer periods of time.
*
* @return Redis|array|false An array of elements or false on failure.
*
* @see https://redis.io/commands/zscan
* @see https://redis.io/commands/scan
* @see Redis::scan()
*
* NOTE: See Redis::scan() for detailed example code on how to call SCAN like commands.
*
*/
public function zscan(string $key, ?int &$iterator, ?string $pattern = null, int $count = 0): Redis|array|false;
/**
* Retrieve the union of one or more sorted sets
*
* @param array $keys One ore more sorted set key names
* @param array $weights An optional array with floating point weights used when performing the union.
* Note that if this argument is passed, it must contain the same number of
* elements as the $keys array.
* @param array $options An array that modifies how this command functions.
*
*
* $options = [
* # By default when members exist in more than one set Redis will SUM
* # total score for each match. Instead, it can return the AVG, MIN,
* # or MAX value based on this option.
* 'AGGREGATE' => 'sum' | 'min' | 'max'
*
* # Whether Redis should also return each members aggregated score.
* 'WITHSCORES' => true | false
* ]
*
*
* @return Redis|array|false The union of each sorted set or false on failure
*
* @example
* $redis->del('store1', 'store2', 'store3');
* $redis->zAdd('store1', 1, 'apples', 3, 'pears', 6, 'bananas');
* $redis->zAdd('store2', 3, 'apples', 5, 'coconuts', 2, 'bananas');
* $redis->zAdd('store3', 2, 'bananas', 6, 'apples', 4, 'figs');
*
* $redis->zUnion(['store1', 'store2', 'store3'], NULL, ['withscores' => true]);
* $redis->zUnion(['store1', 'store3'], [2, .5], ['withscores' => true]);
* $redis->zUnion(['store1', 'store3'], [2, .5], ['withscores' => true, 'aggregate' => 'MIN']);
*/
public function zunion(array $keys, ?array $weights = null, ?array $options = null): Redis|array|false;
/**
* Perform a union on one or more Redis sets and store the result in a destination sorted set.
*
* @param string $dst The destination set to store the union.
* @param array $keys One or more input keys on which to perform our union.
* @param array $weights An optional weights array used to weight each input set.
* @param string $aggregate An optional modifier in how Redis will combine duplicate members.
* Valid: 'MIN', 'MAX', 'SUM'.
*
* @return Redis|int|false The number of members stored in the destination set or false on failure.
*
* @see https://redis.io/commands/zunionstore
* @see Redis::zunion()
*
* @example
* $redis->zAdd('zs1', 1, 'one', 3, 'three');
* $redis->zAdd('zs1', 2, 'two', 4, 'four');
* $redis->zadd('zs3', 1, 'one', 7, 'five');
*
* $redis->zUnionStore('dst', ['zs1', 'zs2', 'zs3']);
*/
public function zunionstore(string $dst, array $keys, ?array $weights = null, ?string $aggregate = null): Redis|int|false;
}
class RedisException extends RuntimeException {}
redis-6.0.2/redis_arginfo.h 0000644 0001750 0000012 00000303773 14515245367 016421 0 ustar pyatsukhnenko wheel /* This is a generated file, edit the .stub.php file instead.
* Stub hash: 8cf0ecc2f5a43c6ede68d537a76faa23cb912d96 */
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___construct, 0, 0, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___destruct, 0, 0, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis__compress, 0, 1, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis__uncompress arginfo_class_Redis__compress
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis__prefix, 0, 1, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis__serialize, 0, 1, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis__unserialize, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis__pack arginfo_class_Redis__serialize
#define arginfo_class_Redis__unpack arginfo_class_Redis__unserialize
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_acl, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, subcmd, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, args, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_append, 0, 2, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_auth, 0, 1, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, credentials, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_bgSave, 0, 0, Redis, MAY_BE_BOOL)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_bgrewriteaof arginfo_class_Redis_bgSave
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_bitcount, 0, 1, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, start, IS_LONG, 0, "0")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, end, IS_LONG, 0, "-1")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, bybit, _IS_BOOL, 0, "false")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_bitop, 0, 3, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, operation, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, deskey, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, srckey, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_keys, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_bitpos, 0, 2, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, bit, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, start, IS_LONG, 0, "0")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, end, IS_LONG, 0, "-1")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, bybit, _IS_BOOL, 0, "false")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_blPop, 0, 2, Redis, MAY_BE_ARRAY|MAY_BE_NULL|MAY_BE_FALSE)
ZEND_ARG_TYPE_MASK(0, key_or_keys, MAY_BE_STRING|MAY_BE_ARRAY, NULL)
ZEND_ARG_TYPE_MASK(0, timeout_or_key, MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_LONG, NULL)
ZEND_ARG_VARIADIC_TYPE_INFO(0, extra_args, IS_MIXED, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_brPop arginfo_class_Redis_blPop
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_brpoplpush, 0, 3, Redis, MAY_BE_STRING|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, src, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0)
ZEND_ARG_TYPE_MASK(0, timeout, MAY_BE_LONG|MAY_BE_DOUBLE, NULL)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_bzPopMax, 0, 2, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_MASK(0, key, MAY_BE_STRING|MAY_BE_ARRAY, NULL)
ZEND_ARG_TYPE_MASK(0, timeout_or_key, MAY_BE_STRING|MAY_BE_LONG, NULL)
ZEND_ARG_VARIADIC_TYPE_INFO(0, extra_args, IS_MIXED, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_bzPopMin arginfo_class_Redis_bzPopMax
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_bzmpop, 0, 3, Redis, MAY_BE_ARRAY|MAY_BE_NULL|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, timeout, IS_DOUBLE, 0)
ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO(0, from, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "1")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zmpop, 0, 2, Redis, MAY_BE_ARRAY|MAY_BE_NULL|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO(0, from, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "1")
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_blmpop arginfo_class_Redis_bzmpop
#define arginfo_class_Redis_lmpop arginfo_class_Redis_zmpop
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_clearLastError, 0, 0, _IS_BOOL, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_client, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, opt, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, args, IS_MIXED, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_close arginfo_class_Redis_clearLastError
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_command, 0, 0, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, opt, IS_STRING, 1, "null")
ZEND_ARG_VARIADIC_TYPE_INFO(0, args, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_config, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, operation, IS_STRING, 0)
ZEND_ARG_TYPE_MASK(0, key_or_settings, MAY_BE_ARRAY|MAY_BE_STRING|MAY_BE_NULL, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, value, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_connect, 0, 1, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO(0, host, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, port, IS_LONG, 0, "6379")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, timeout, IS_DOUBLE, 0, "0")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, persistent_id, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, retry_interval, IS_LONG, 0, "0")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, read_timeout, IS_DOUBLE, 0, "0")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, context, IS_ARRAY, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_copy, 0, 2, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, src, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_dbSize, 0, 0, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_debug, 0, 1, Redis, MAY_BE_STRING)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_decr, 0, 1, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, by, IS_LONG, 0, "1")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_decrBy, 0, 2, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_del, 0, 1, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_MASK(0, key, MAY_BE_ARRAY|MAY_BE_STRING, NULL)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_keys, IS_STRING, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_delete arginfo_class_Redis_del
#define arginfo_class_Redis_discard arginfo_class_Redis_bgSave
#define arginfo_class_Redis_dump arginfo_class_Redis_debug
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_echo, 0, 1, Redis, MAY_BE_STRING|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_eval, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, script, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, args, IS_ARRAY, 0, "[]")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, num_keys, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_eval_ro, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, script_sha, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, args, IS_ARRAY, 0, "[]")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, num_keys, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_evalsha, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, sha1, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, args, IS_ARRAY, 0, "[]")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, num_keys, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_evalsha_ro arginfo_class_Redis_evalsha
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_exec, 0, 0, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_exists, 0, 1, Redis, MAY_BE_LONG|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_MIXED, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_keys, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_expire, 0, 2, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, timeout, IS_LONG, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_expireAt, 0, 2, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, timestamp, IS_LONG, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_failover, 0, 0, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, to, IS_ARRAY, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, abort, _IS_BOOL, 0, "false")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, timeout, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_expiretime, 0, 1, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_pexpiretime arginfo_class_Redis_expiretime
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_fcall, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, fn, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, keys, IS_ARRAY, 0, "[]")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, args, IS_ARRAY, 0, "[]")
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_fcall_ro arginfo_class_Redis_fcall
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_flushAll, 0, 0, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, sync, _IS_BOOL, 1, "null")
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_flushDB arginfo_class_Redis_flushAll
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_function, 0, 1, Redis, MAY_BE_BOOL|MAY_BE_STRING|MAY_BE_ARRAY)
ZEND_ARG_TYPE_INFO(0, operation, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, args, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_geoadd, 0, 4, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, lng, IS_DOUBLE, 0)
ZEND_ARG_TYPE_INFO(0, lat, IS_DOUBLE, 0)
ZEND_ARG_TYPE_INFO(0, member, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_triples_and_options, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_geodist, 0, 3, Redis, MAY_BE_DOUBLE|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, src, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, unit, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_geohash, 0, 2, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, member, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_members, IS_STRING, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_geopos arginfo_class_Redis_geohash
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_georadius, 0, 5, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, lng, IS_DOUBLE, 0)
ZEND_ARG_TYPE_INFO(0, lat, IS_DOUBLE, 0)
ZEND_ARG_TYPE_INFO(0, radius, IS_DOUBLE, 0)
ZEND_ARG_TYPE_INFO(0, unit, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "[]")
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_georadius_ro arginfo_class_Redis_georadius
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_georadiusbymember, 0, 4, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, member, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, radius, IS_DOUBLE, 0)
ZEND_ARG_TYPE_INFO(0, unit, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "[]")
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_georadiusbymember_ro arginfo_class_Redis_georadiusbymember
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_geosearch, 0, 4, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_MASK(0, position, MAY_BE_ARRAY|MAY_BE_STRING, NULL)
ZEND_ARG_TYPE_MASK(0, shape, MAY_BE_ARRAY|MAY_BE_LONG|MAY_BE_DOUBLE, NULL)
ZEND_ARG_TYPE_INFO(0, unit, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "[]")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_geosearchstore, 0, 5, Redis, MAY_BE_ARRAY|MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, src, IS_STRING, 0)
ZEND_ARG_TYPE_MASK(0, position, MAY_BE_ARRAY|MAY_BE_STRING, NULL)
ZEND_ARG_TYPE_MASK(0, shape, MAY_BE_ARRAY|MAY_BE_LONG|MAY_BE_DOUBLE, NULL)
ZEND_ARG_TYPE_INFO(0, unit, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "[]")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_get, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_getAuth, 0, 0, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_getBit, 0, 2, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, idx, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_getEx, 0, 1, Redis, MAY_BE_STRING|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "[]")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_getDBNum, 0, 0, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_getDel, 0, 1, Redis, MAY_BE_STRING|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_getHost, 0, 0, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_getLastError, 0, 0, IS_STRING, 1)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_getMode arginfo_class_Redis_getDBNum
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_getOption, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, option, IS_LONG, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_getPersistentID arginfo_class_Redis_getLastError
#define arginfo_class_Redis_getPort arginfo_class_Redis_getDBNum
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_getRange, 0, 3, Redis, MAY_BE_STRING|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, start, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, end, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_lcs, 0, 2, Redis, MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key1, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, key2, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_getReadTimeout, 0, 0, IS_DOUBLE, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_getset, 0, 2, Redis, MAY_BE_STRING|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_Redis_getTimeout, 0, 0, MAY_BE_DOUBLE|MAY_BE_FALSE)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_getTransferredBytes, 0, 0, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_clearTransferredBytes, 0, 0, IS_VOID, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_hDel, 0, 2, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, field, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_fields, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_hExists, 0, 2, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, field, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_hGet, 0, 2, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, member, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_hGetAll, 0, 1, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_hIncrBy, 0, 3, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, field, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_hIncrByFloat, 0, 3, Redis, MAY_BE_DOUBLE|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, field, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_DOUBLE, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_hKeys arginfo_class_Redis_hGetAll
#define arginfo_class_Redis_hLen arginfo_class_Redis_expiretime
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_hMget, 0, 2, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, fields, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_hMset, 0, 2, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, fieldvals, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_hRandField, 0, 1, Redis, MAY_BE_STRING|MAY_BE_ARRAY)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_hSet, 0, 3, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, member, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_hSetNx, 0, 3, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, field, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_hStrLen, 0, 2, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, field, IS_STRING, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_hVals arginfo_class_Redis_hGetAll
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_hscan, 0, 2, Redis, MAY_BE_ARRAY|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(1, iterator, IS_LONG, 1)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, pattern, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_incr arginfo_class_Redis_decr
#define arginfo_class_Redis_incrBy arginfo_class_Redis_decrBy
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_incrByFloat, 0, 2, Redis, MAY_BE_DOUBLE|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_DOUBLE, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_info, 0, 0, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_VARIADIC_TYPE_INFO(0, sections, IS_STRING, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_isConnected arginfo_class_Redis_clearLastError
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_keys, 0, 0, 1)
ZEND_ARG_TYPE_INFO(0, pattern, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_lInsert, 0, 0, 4)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, pos, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, pivot, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_lLen arginfo_class_Redis_expiretime
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_lMove, 0, 4, Redis, MAY_BE_STRING|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, src, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, wherefrom, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, whereto, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_blmove, 0, 5, Redis, MAY_BE_STRING|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, src, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, wherefrom, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, whereto, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, timeout, IS_DOUBLE, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_lPop, 0, 1, Redis, MAY_BE_BOOL|MAY_BE_STRING|MAY_BE_ARRAY)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_lPos, 0, 2, Redis, MAY_BE_NULL|MAY_BE_BOOL|MAY_BE_LONG|MAY_BE_ARRAY)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_lPush, 0, 1, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, elements, IS_MIXED, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_rPush arginfo_class_Redis_lPush
#define arginfo_class_Redis_lPushx arginfo_class_Redis_append
#define arginfo_class_Redis_rPushx arginfo_class_Redis_append
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_lSet, 0, 3, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, index, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_lastSave arginfo_class_Redis_getDBNum
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_lindex, 0, 2, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, index, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_lrange, 0, 3, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, start, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, end, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_lrem, 0, 2, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_ltrim, 0, 3, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, start, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, end, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_mget, 0, 1, Redis, MAY_BE_ARRAY)
ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_migrate, 0, 5, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, host, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, port, IS_LONG, 0)
ZEND_ARG_TYPE_MASK(0, key, MAY_BE_STRING|MAY_BE_ARRAY, NULL)
ZEND_ARG_TYPE_INFO(0, dstdb, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, timeout, IS_LONG, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, copy, _IS_BOOL, 0, "false")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, replace, _IS_BOOL, 0, "false")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, credentials, IS_MIXED, 0, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_move, 0, 2, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, index, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_mset, 0, 1, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key_values, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_msetnx arginfo_class_Redis_mset
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_multi, 0, 0, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, value, IS_LONG, 0, "Redis::MULTI")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_object, 0, 2, Redis, MAY_BE_LONG|MAY_BE_STRING|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, subcommand, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_open, 0, 1, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO(0, host, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, port, IS_LONG, 0, "6379")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, timeout, IS_DOUBLE, 0, "0")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, persistent_id, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, retry_interval, IS_LONG, 0, "0")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, read_timeout, IS_DOUBLE, 0, "0")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, context, IS_ARRAY, 1, "null")
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_pconnect arginfo_class_Redis_open
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_persist, 0, 1, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_pexpire, 0, 2, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, timeout, IS_LONG, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_pexpireAt arginfo_class_Redis_expireAt
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_pfadd, 0, 2, Redis, MAY_BE_LONG)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, elements, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_pfcount, 0, 1, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_MASK(0, key_or_keys, MAY_BE_ARRAY|MAY_BE_STRING, NULL)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_pfmerge, 0, 2, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, srckeys, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_ping, 0, 0, Redis, MAY_BE_STRING|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, message, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_pipeline, 0, 0, Redis, MAY_BE_BOOL)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_popen arginfo_class_Redis_open
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_psetex, 0, 3, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, expire, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_psubscribe, 0, 2, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO(0, patterns, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO(0, cb, IS_CALLABLE, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_pttl arginfo_class_Redis_expiretime
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_publish, 0, 2, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, channel, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, message, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_pubsub, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, command, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, arg, IS_MIXED, 0, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_punsubscribe, 0, 1, Redis, MAY_BE_ARRAY|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, patterns, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_rPop, 0, 1, Redis, MAY_BE_ARRAY|MAY_BE_STRING|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_randomKey, 0, 0, Redis, MAY_BE_STRING|MAY_BE_FALSE)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_rawcommand, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, command, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, args, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_rename, 0, 2, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, old_name, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, new_name, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_renameNx, 0, 2, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key_src, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, key_dst, IS_STRING, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_reset arginfo_class_Redis_bgSave
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_restore, 0, 3, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, ttl, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null")
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_role arginfo_class_Redis_getAuth
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_rpoplpush, 0, 2, Redis, MAY_BE_STRING|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, srckey, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, dstkey, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_sAdd, 0, 2, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_values, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_sAddArray, 0, 2, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, values, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_sDiff, 0, 1, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_keys, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_sDiffStore, 0, 2, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_keys, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_sInter, 0, 1, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_MASK(0, key, MAY_BE_ARRAY|MAY_BE_STRING, NULL)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_keys, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_sintercard, 0, 1, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, limit, IS_LONG, 0, "-1")
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_sInterStore arginfo_class_Redis_del
#define arginfo_class_Redis_sMembers arginfo_class_Redis_hGetAll
#define arginfo_class_Redis_sMisMember arginfo_class_Redis_geohash
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_sMove, 0, 3, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, src, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_sPop, 0, 1, Redis, MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_sRandMember arginfo_class_Redis_sPop
#define arginfo_class_Redis_sUnion arginfo_class_Redis_sDiff
#define arginfo_class_Redis_sUnionStore arginfo_class_Redis_sDiffStore
#define arginfo_class_Redis_save arginfo_class_Redis_bgSave
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_Redis_scan, 0, 1, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(1, iterator, IS_LONG, 1)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, pattern, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "0")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, type, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_scard arginfo_class_Redis_expiretime
#define arginfo_class_Redis_script arginfo_class_Redis_rawcommand
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_select, 0, 1, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, db, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_set, 0, 2, Redis, MAY_BE_STRING|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_MIXED, 0, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_setBit, 0, 3, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, idx, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, value, _IS_BOOL, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_setRange, 0, 3, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, index, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_setOption, 0, 2, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO(0, option, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_setex, 0, 0, 3)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, expire, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_setnx, 0, 2, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_sismember arginfo_class_Redis_setnx
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_slaveof, 0, 0, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, host, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, port, IS_LONG, 0, "6379")
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_replicaof arginfo_class_Redis_slaveof
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_touch, 0, 1, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_MASK(0, key_or_array, MAY_BE_ARRAY|MAY_BE_STRING, NULL)
ZEND_ARG_VARIADIC_TYPE_INFO(0, more_keys, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_slowlog, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, operation, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, length, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_sort, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null")
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_sort_ro arginfo_class_Redis_sort
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_sortAsc, 0, 1, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, pattern, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, get, IS_MIXED, 0, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, offset, IS_LONG, 0, "-1")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "-1")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, store, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_sortAscAlpha arginfo_class_Redis_sortAsc
#define arginfo_class_Redis_sortDesc arginfo_class_Redis_sortAsc
#define arginfo_class_Redis_sortDescAlpha arginfo_class_Redis_sortAsc
#define arginfo_class_Redis_srem arginfo_class_Redis_sAdd
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_Redis_sscan, 0, 2, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(1, iterator, IS_LONG, 1)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, pattern, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_ssubscribe, 0, 2, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO(0, channels, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO(0, cb, IS_CALLABLE, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_strlen arginfo_class_Redis_expiretime
#define arginfo_class_Redis_subscribe arginfo_class_Redis_ssubscribe
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_sunsubscribe, 0, 1, Redis, MAY_BE_ARRAY|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, channels, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_swapdb, 0, 2, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, src, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, dst, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_time, 0, 0, Redis, MAY_BE_ARRAY)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_ttl arginfo_class_Redis_expiretime
#define arginfo_class_Redis_type arginfo_class_Redis_expiretime
#define arginfo_class_Redis_unlink arginfo_class_Redis_del
#define arginfo_class_Redis_unsubscribe arginfo_class_Redis_sunsubscribe
#define arginfo_class_Redis_unwatch arginfo_class_Redis_bgSave
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_watch, 0, 1, Redis, MAY_BE_BOOL)
ZEND_ARG_TYPE_MASK(0, key, MAY_BE_ARRAY|MAY_BE_STRING, NULL)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_keys, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_Redis_wait, 0, 2, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, numreplicas, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, timeout, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_Redis_xack, 0, 3, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, group, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, ids, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_xadd, 0, 3, Redis, MAY_BE_STRING|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, id, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, values, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, maxlen, IS_LONG, 0, "0")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, approx, _IS_BOOL, 0, "false")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, nomkstream, _IS_BOOL, 0, "false")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_xautoclaim, 0, 5, Redis, MAY_BE_BOOL|MAY_BE_ARRAY)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, group, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, consumer, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, min_idle, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, start, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "-1")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, justid, _IS_BOOL, 0, "false")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_xclaim, 0, 6, Redis, MAY_BE_ARRAY|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, group, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, consumer, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, min_idle, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, ids, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO(0, options, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_xdel, 0, 2, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, ids, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_xgroup, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, operation, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, key, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, group, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, id_or_consumer, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mkstream, _IS_BOOL, 0, "false")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, entries_read, IS_LONG, 0, "-2")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_xinfo, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, operation, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, arg1, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, arg2, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "-1")
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_xlen arginfo_class_Redis_expiretime
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_xpending, 0, 2, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, group, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, start, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, end, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "-1")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, consumer, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_xrange, 0, 3, Redis, MAY_BE_ARRAY|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, start, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, end, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "-1")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_xread, 0, 1, Redis, MAY_BE_ARRAY|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, streams, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "-1")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, block, IS_LONG, 0, "-1")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_xreadgroup, 0, 3, Redis, MAY_BE_ARRAY|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, group, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, consumer, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, streams, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "1")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, block, IS_LONG, 0, "1")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_xrevrange, 0, 3, Redis, MAY_BE_ARRAY|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, end, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, start, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "-1")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_xtrim, 0, 2, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, threshold, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, approx, _IS_BOOL, 0, "false")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, minid, _IS_BOOL, 0, "false")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, limit, IS_LONG, 0, "-1")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zAdd, 0, 2, Redis, MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_MASK(0, score_or_options, MAY_BE_ARRAY|MAY_BE_DOUBLE, NULL)
ZEND_ARG_VARIADIC_TYPE_INFO(0, more_scores_and_mems, IS_MIXED, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_zCard arginfo_class_Redis_expiretime
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zCount, 0, 3, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, start, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, end, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zIncrBy, 0, 3, Redis, MAY_BE_DOUBLE|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_DOUBLE, 0)
ZEND_ARG_TYPE_INFO(0, member, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zLexCount, 0, 3, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, min, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, max, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zMscore, 0, 2, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, member, IS_MIXED, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_members, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zPopMax, 0, 1, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 1, "null")
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_zPopMin arginfo_class_Redis_zPopMax
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zRange, 0, 3, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_MASK(0, start, MAY_BE_STRING|MAY_BE_LONG, NULL)
ZEND_ARG_TYPE_MASK(0, end, MAY_BE_STRING|MAY_BE_LONG, NULL)
ZEND_ARG_TYPE_MASK(0, options, MAY_BE_ARRAY|MAY_BE_BOOL|MAY_BE_NULL, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zRangeByLex, 0, 3, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, min, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, max, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, offset, IS_LONG, 0, "-1")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "-1")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zRangeByScore, 0, 3, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, start, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, end, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "[]")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zrangestore, 0, 4, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, dstkey, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, srckey, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, start, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, end, IS_STRING, 0)
ZEND_ARG_TYPE_MASK(0, options, MAY_BE_ARRAY|MAY_BE_BOOL|MAY_BE_NULL, "null")
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_zRandMember arginfo_class_Redis_hRandField
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zRank, 0, 2, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, member, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zRem, 0, 2, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, member, IS_MIXED, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_members, IS_MIXED, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_zRemRangeByLex arginfo_class_Redis_zLexCount
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zRemRangeByRank, 0, 3, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, start, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, end, IS_LONG, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_zRemRangeByScore arginfo_class_Redis_zCount
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zRevRange, 0, 3, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, start, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, end, IS_LONG, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, scores, IS_MIXED, 0, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zRevRangeByLex, 0, 3, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, max, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, min, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, offset, IS_LONG, 0, "-1")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "-1")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zRevRangeByScore, 0, 3, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, max, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, min, IS_STRING, 0)
ZEND_ARG_TYPE_MASK(0, options, MAY_BE_ARRAY|MAY_BE_BOOL, "[]")
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_zRevRank arginfo_class_Redis_zRank
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zScore, 0, 2, Redis, MAY_BE_DOUBLE|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, member, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zdiff, 0, 1, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zdiffstore, 0, 2, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zinter, 0, 1, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, weights, IS_ARRAY, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null")
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_zintercard arginfo_class_Redis_sintercard
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zinterstore, 0, 2, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, weights, IS_ARRAY, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, aggregate, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zscan, 0, 2, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(1, iterator, IS_LONG, 1)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, pattern, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_zunion arginfo_class_Redis_zinter
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zunionstore, 0, 2, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, weights, IS_ARRAY, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, aggregate, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
ZEND_METHOD(Redis, __construct);
ZEND_METHOD(Redis, __destruct);
ZEND_METHOD(Redis, _compress);
ZEND_METHOD(Redis, _uncompress);
ZEND_METHOD(Redis, _prefix);
ZEND_METHOD(Redis, _serialize);
ZEND_METHOD(Redis, _unserialize);
ZEND_METHOD(Redis, _pack);
ZEND_METHOD(Redis, _unpack);
ZEND_METHOD(Redis, acl);
ZEND_METHOD(Redis, append);
ZEND_METHOD(Redis, auth);
ZEND_METHOD(Redis, bgSave);
ZEND_METHOD(Redis, bgrewriteaof);
ZEND_METHOD(Redis, bitcount);
ZEND_METHOD(Redis, bitop);
ZEND_METHOD(Redis, bitpos);
ZEND_METHOD(Redis, blPop);
ZEND_METHOD(Redis, brPop);
ZEND_METHOD(Redis, brpoplpush);
ZEND_METHOD(Redis, bzPopMax);
ZEND_METHOD(Redis, bzPopMin);
ZEND_METHOD(Redis, bzmpop);
ZEND_METHOD(Redis, zmpop);
ZEND_METHOD(Redis, blmpop);
ZEND_METHOD(Redis, lmpop);
ZEND_METHOD(Redis, clearLastError);
ZEND_METHOD(Redis, client);
ZEND_METHOD(Redis, close);
ZEND_METHOD(Redis, command);
ZEND_METHOD(Redis, config);
ZEND_METHOD(Redis, connect);
ZEND_METHOD(Redis, copy);
ZEND_METHOD(Redis, dbSize);
ZEND_METHOD(Redis, debug);
ZEND_METHOD(Redis, decr);
ZEND_METHOD(Redis, decrBy);
ZEND_METHOD(Redis, del);
ZEND_METHOD(Redis, discard);
ZEND_METHOD(Redis, dump);
ZEND_METHOD(Redis, echo);
ZEND_METHOD(Redis, eval);
ZEND_METHOD(Redis, eval_ro);
ZEND_METHOD(Redis, evalsha);
ZEND_METHOD(Redis, evalsha_ro);
ZEND_METHOD(Redis, exec);
ZEND_METHOD(Redis, exists);
ZEND_METHOD(Redis, expire);
ZEND_METHOD(Redis, expireAt);
ZEND_METHOD(Redis, failover);
ZEND_METHOD(Redis, expiretime);
ZEND_METHOD(Redis, pexpiretime);
ZEND_METHOD(Redis, fcall);
ZEND_METHOD(Redis, fcall_ro);
ZEND_METHOD(Redis, flushAll);
ZEND_METHOD(Redis, flushDB);
ZEND_METHOD(Redis, function);
ZEND_METHOD(Redis, geoadd);
ZEND_METHOD(Redis, geodist);
ZEND_METHOD(Redis, geohash);
ZEND_METHOD(Redis, geopos);
ZEND_METHOD(Redis, georadius);
ZEND_METHOD(Redis, georadius_ro);
ZEND_METHOD(Redis, georadiusbymember);
ZEND_METHOD(Redis, georadiusbymember_ro);
ZEND_METHOD(Redis, geosearch);
ZEND_METHOD(Redis, geosearchstore);
ZEND_METHOD(Redis, get);
ZEND_METHOD(Redis, getAuth);
ZEND_METHOD(Redis, getBit);
ZEND_METHOD(Redis, getEx);
ZEND_METHOD(Redis, getDBNum);
ZEND_METHOD(Redis, getDel);
ZEND_METHOD(Redis, getHost);
ZEND_METHOD(Redis, getLastError);
ZEND_METHOD(Redis, getMode);
ZEND_METHOD(Redis, getOption);
ZEND_METHOD(Redis, getPersistentID);
ZEND_METHOD(Redis, getPort);
ZEND_METHOD(Redis, getRange);
ZEND_METHOD(Redis, lcs);
ZEND_METHOD(Redis, getReadTimeout);
ZEND_METHOD(Redis, getset);
ZEND_METHOD(Redis, getTimeout);
ZEND_METHOD(Redis, getTransferredBytes);
ZEND_METHOD(Redis, clearTransferredBytes);
ZEND_METHOD(Redis, hDel);
ZEND_METHOD(Redis, hExists);
ZEND_METHOD(Redis, hGet);
ZEND_METHOD(Redis, hGetAll);
ZEND_METHOD(Redis, hIncrBy);
ZEND_METHOD(Redis, hIncrByFloat);
ZEND_METHOD(Redis, hKeys);
ZEND_METHOD(Redis, hLen);
ZEND_METHOD(Redis, hMget);
ZEND_METHOD(Redis, hMset);
ZEND_METHOD(Redis, hRandField);
ZEND_METHOD(Redis, hSet);
ZEND_METHOD(Redis, hSetNx);
ZEND_METHOD(Redis, hStrLen);
ZEND_METHOD(Redis, hVals);
ZEND_METHOD(Redis, hscan);
ZEND_METHOD(Redis, incr);
ZEND_METHOD(Redis, incrBy);
ZEND_METHOD(Redis, incrByFloat);
ZEND_METHOD(Redis, info);
ZEND_METHOD(Redis, isConnected);
ZEND_METHOD(Redis, keys);
ZEND_METHOD(Redis, lInsert);
ZEND_METHOD(Redis, lLen);
ZEND_METHOD(Redis, lMove);
ZEND_METHOD(Redis, blmove);
ZEND_METHOD(Redis, lPop);
ZEND_METHOD(Redis, lPos);
ZEND_METHOD(Redis, lPush);
ZEND_METHOD(Redis, rPush);
ZEND_METHOD(Redis, lPushx);
ZEND_METHOD(Redis, rPushx);
ZEND_METHOD(Redis, lSet);
ZEND_METHOD(Redis, lastSave);
ZEND_METHOD(Redis, lindex);
ZEND_METHOD(Redis, lrange);
ZEND_METHOD(Redis, lrem);
ZEND_METHOD(Redis, ltrim);
ZEND_METHOD(Redis, mget);
ZEND_METHOD(Redis, migrate);
ZEND_METHOD(Redis, move);
ZEND_METHOD(Redis, mset);
ZEND_METHOD(Redis, msetnx);
ZEND_METHOD(Redis, multi);
ZEND_METHOD(Redis, object);
ZEND_METHOD(Redis, pconnect);
ZEND_METHOD(Redis, persist);
ZEND_METHOD(Redis, pexpire);
ZEND_METHOD(Redis, pexpireAt);
ZEND_METHOD(Redis, pfadd);
ZEND_METHOD(Redis, pfcount);
ZEND_METHOD(Redis, pfmerge);
ZEND_METHOD(Redis, ping);
ZEND_METHOD(Redis, pipeline);
ZEND_METHOD(Redis, psetex);
ZEND_METHOD(Redis, psubscribe);
ZEND_METHOD(Redis, pttl);
ZEND_METHOD(Redis, publish);
ZEND_METHOD(Redis, pubsub);
ZEND_METHOD(Redis, punsubscribe);
ZEND_METHOD(Redis, rPop);
ZEND_METHOD(Redis, randomKey);
ZEND_METHOD(Redis, rawcommand);
ZEND_METHOD(Redis, rename);
ZEND_METHOD(Redis, renameNx);
ZEND_METHOD(Redis, reset);
ZEND_METHOD(Redis, restore);
ZEND_METHOD(Redis, role);
ZEND_METHOD(Redis, rpoplpush);
ZEND_METHOD(Redis, sAdd);
ZEND_METHOD(Redis, sAddArray);
ZEND_METHOD(Redis, sDiff);
ZEND_METHOD(Redis, sDiffStore);
ZEND_METHOD(Redis, sInter);
ZEND_METHOD(Redis, sintercard);
ZEND_METHOD(Redis, sInterStore);
ZEND_METHOD(Redis, sMembers);
ZEND_METHOD(Redis, sMisMember);
ZEND_METHOD(Redis, sMove);
ZEND_METHOD(Redis, sPop);
ZEND_METHOD(Redis, sRandMember);
ZEND_METHOD(Redis, sUnion);
ZEND_METHOD(Redis, sUnionStore);
ZEND_METHOD(Redis, save);
ZEND_METHOD(Redis, scan);
ZEND_METHOD(Redis, scard);
ZEND_METHOD(Redis, script);
ZEND_METHOD(Redis, select);
ZEND_METHOD(Redis, set);
ZEND_METHOD(Redis, setBit);
ZEND_METHOD(Redis, setRange);
ZEND_METHOD(Redis, setOption);
ZEND_METHOD(Redis, setex);
ZEND_METHOD(Redis, setnx);
ZEND_METHOD(Redis, sismember);
ZEND_METHOD(Redis, slaveof);
ZEND_METHOD(Redis, replicaof);
ZEND_METHOD(Redis, touch);
ZEND_METHOD(Redis, slowlog);
ZEND_METHOD(Redis, sort);
ZEND_METHOD(Redis, sort_ro);
ZEND_METHOD(Redis, sortAsc);
ZEND_METHOD(Redis, sortAscAlpha);
ZEND_METHOD(Redis, sortDesc);
ZEND_METHOD(Redis, sortDescAlpha);
ZEND_METHOD(Redis, srem);
ZEND_METHOD(Redis, sscan);
ZEND_METHOD(Redis, ssubscribe);
ZEND_METHOD(Redis, strlen);
ZEND_METHOD(Redis, subscribe);
ZEND_METHOD(Redis, sunsubscribe);
ZEND_METHOD(Redis, swapdb);
ZEND_METHOD(Redis, time);
ZEND_METHOD(Redis, ttl);
ZEND_METHOD(Redis, type);
ZEND_METHOD(Redis, unlink);
ZEND_METHOD(Redis, unsubscribe);
ZEND_METHOD(Redis, unwatch);
ZEND_METHOD(Redis, watch);
ZEND_METHOD(Redis, wait);
ZEND_METHOD(Redis, xack);
ZEND_METHOD(Redis, xadd);
ZEND_METHOD(Redis, xautoclaim);
ZEND_METHOD(Redis, xclaim);
ZEND_METHOD(Redis, xdel);
ZEND_METHOD(Redis, xgroup);
ZEND_METHOD(Redis, xinfo);
ZEND_METHOD(Redis, xlen);
ZEND_METHOD(Redis, xpending);
ZEND_METHOD(Redis, xrange);
ZEND_METHOD(Redis, xread);
ZEND_METHOD(Redis, xreadgroup);
ZEND_METHOD(Redis, xrevrange);
ZEND_METHOD(Redis, xtrim);
ZEND_METHOD(Redis, zAdd);
ZEND_METHOD(Redis, zCard);
ZEND_METHOD(Redis, zCount);
ZEND_METHOD(Redis, zIncrBy);
ZEND_METHOD(Redis, zLexCount);
ZEND_METHOD(Redis, zMscore);
ZEND_METHOD(Redis, zPopMax);
ZEND_METHOD(Redis, zPopMin);
ZEND_METHOD(Redis, zRange);
ZEND_METHOD(Redis, zRangeByLex);
ZEND_METHOD(Redis, zRangeByScore);
ZEND_METHOD(Redis, zrangestore);
ZEND_METHOD(Redis, zRandMember);
ZEND_METHOD(Redis, zRank);
ZEND_METHOD(Redis, zRem);
ZEND_METHOD(Redis, zRemRangeByLex);
ZEND_METHOD(Redis, zRemRangeByRank);
ZEND_METHOD(Redis, zRemRangeByScore);
ZEND_METHOD(Redis, zRevRange);
ZEND_METHOD(Redis, zRevRangeByLex);
ZEND_METHOD(Redis, zRevRangeByScore);
ZEND_METHOD(Redis, zRevRank);
ZEND_METHOD(Redis, zScore);
ZEND_METHOD(Redis, zdiff);
ZEND_METHOD(Redis, zdiffstore);
ZEND_METHOD(Redis, zinter);
ZEND_METHOD(Redis, zintercard);
ZEND_METHOD(Redis, zinterstore);
ZEND_METHOD(Redis, zscan);
ZEND_METHOD(Redis, zunion);
ZEND_METHOD(Redis, zunionstore);
static const zend_function_entry class_Redis_methods[] = {
ZEND_ME(Redis, __construct, arginfo_class_Redis___construct, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, __destruct, arginfo_class_Redis___destruct, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, _compress, arginfo_class_Redis__compress, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, _uncompress, arginfo_class_Redis__uncompress, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, _prefix, arginfo_class_Redis__prefix, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, _serialize, arginfo_class_Redis__serialize, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, _unserialize, arginfo_class_Redis__unserialize, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, _pack, arginfo_class_Redis__pack, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, _unpack, arginfo_class_Redis__unpack, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, acl, arginfo_class_Redis_acl, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, append, arginfo_class_Redis_append, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, auth, arginfo_class_Redis_auth, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, bgSave, arginfo_class_Redis_bgSave, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, bgrewriteaof, arginfo_class_Redis_bgrewriteaof, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, bitcount, arginfo_class_Redis_bitcount, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, bitop, arginfo_class_Redis_bitop, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, bitpos, arginfo_class_Redis_bitpos, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, blPop, arginfo_class_Redis_blPop, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, brPop, arginfo_class_Redis_brPop, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, brpoplpush, arginfo_class_Redis_brpoplpush, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, bzPopMax, arginfo_class_Redis_bzPopMax, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, bzPopMin, arginfo_class_Redis_bzPopMin, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, bzmpop, arginfo_class_Redis_bzmpop, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zmpop, arginfo_class_Redis_zmpop, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, blmpop, arginfo_class_Redis_blmpop, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lmpop, arginfo_class_Redis_lmpop, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, clearLastError, arginfo_class_Redis_clearLastError, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, client, arginfo_class_Redis_client, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, close, arginfo_class_Redis_close, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, command, arginfo_class_Redis_command, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, config, arginfo_class_Redis_config, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, connect, arginfo_class_Redis_connect, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, copy, arginfo_class_Redis_copy, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, dbSize, arginfo_class_Redis_dbSize, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, debug, arginfo_class_Redis_debug, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, decr, arginfo_class_Redis_decr, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, decrBy, arginfo_class_Redis_decrBy, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, del, arginfo_class_Redis_del, ZEND_ACC_PUBLIC)
ZEND_MALIAS(Redis, delete, del, arginfo_class_Redis_delete, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
ZEND_ME(Redis, discard, arginfo_class_Redis_discard, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, dump, arginfo_class_Redis_dump, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, echo, arginfo_class_Redis_echo, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, eval, arginfo_class_Redis_eval, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, eval_ro, arginfo_class_Redis_eval_ro, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, evalsha, arginfo_class_Redis_evalsha, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, evalsha_ro, arginfo_class_Redis_evalsha_ro, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, exec, arginfo_class_Redis_exec, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, exists, arginfo_class_Redis_exists, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, expire, arginfo_class_Redis_expire, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, expireAt, arginfo_class_Redis_expireAt, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, failover, arginfo_class_Redis_failover, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, expiretime, arginfo_class_Redis_expiretime, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, pexpiretime, arginfo_class_Redis_pexpiretime, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, fcall, arginfo_class_Redis_fcall, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, fcall_ro, arginfo_class_Redis_fcall_ro, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, flushAll, arginfo_class_Redis_flushAll, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, flushDB, arginfo_class_Redis_flushDB, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, function, arginfo_class_Redis_function, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, geoadd, arginfo_class_Redis_geoadd, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, geodist, arginfo_class_Redis_geodist, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, geohash, arginfo_class_Redis_geohash, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, geopos, arginfo_class_Redis_geopos, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, georadius, arginfo_class_Redis_georadius, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, georadius_ro, arginfo_class_Redis_georadius_ro, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, georadiusbymember, arginfo_class_Redis_georadiusbymember, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, georadiusbymember_ro, arginfo_class_Redis_georadiusbymember_ro, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, geosearch, arginfo_class_Redis_geosearch, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, geosearchstore, arginfo_class_Redis_geosearchstore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, get, arginfo_class_Redis_get, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getAuth, arginfo_class_Redis_getAuth, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getBit, arginfo_class_Redis_getBit, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getEx, arginfo_class_Redis_getEx, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getDBNum, arginfo_class_Redis_getDBNum, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getDel, arginfo_class_Redis_getDel, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getHost, arginfo_class_Redis_getHost, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getLastError, arginfo_class_Redis_getLastError, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getMode, arginfo_class_Redis_getMode, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getOption, arginfo_class_Redis_getOption, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getPersistentID, arginfo_class_Redis_getPersistentID, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getPort, arginfo_class_Redis_getPort, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getRange, arginfo_class_Redis_getRange, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lcs, arginfo_class_Redis_lcs, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getReadTimeout, arginfo_class_Redis_getReadTimeout, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getset, arginfo_class_Redis_getset, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getTimeout, arginfo_class_Redis_getTimeout, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getTransferredBytes, arginfo_class_Redis_getTransferredBytes, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, clearTransferredBytes, arginfo_class_Redis_clearTransferredBytes, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hDel, arginfo_class_Redis_hDel, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hExists, arginfo_class_Redis_hExists, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hGet, arginfo_class_Redis_hGet, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hGetAll, arginfo_class_Redis_hGetAll, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hIncrBy, arginfo_class_Redis_hIncrBy, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hIncrByFloat, arginfo_class_Redis_hIncrByFloat, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hKeys, arginfo_class_Redis_hKeys, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hLen, arginfo_class_Redis_hLen, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hMget, arginfo_class_Redis_hMget, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hMset, arginfo_class_Redis_hMset, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hRandField, arginfo_class_Redis_hRandField, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hSet, arginfo_class_Redis_hSet, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hSetNx, arginfo_class_Redis_hSetNx, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hStrLen, arginfo_class_Redis_hStrLen, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hVals, arginfo_class_Redis_hVals, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hscan, arginfo_class_Redis_hscan, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, incr, arginfo_class_Redis_incr, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, incrBy, arginfo_class_Redis_incrBy, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, incrByFloat, arginfo_class_Redis_incrByFloat, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, info, arginfo_class_Redis_info, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, isConnected, arginfo_class_Redis_isConnected, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, keys, arginfo_class_Redis_keys, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lInsert, arginfo_class_Redis_lInsert, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lLen, arginfo_class_Redis_lLen, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lMove, arginfo_class_Redis_lMove, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, blmove, arginfo_class_Redis_blmove, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lPop, arginfo_class_Redis_lPop, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lPos, arginfo_class_Redis_lPos, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lPush, arginfo_class_Redis_lPush, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, rPush, arginfo_class_Redis_rPush, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lPushx, arginfo_class_Redis_lPushx, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, rPushx, arginfo_class_Redis_rPushx, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lSet, arginfo_class_Redis_lSet, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lastSave, arginfo_class_Redis_lastSave, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lindex, arginfo_class_Redis_lindex, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lrange, arginfo_class_Redis_lrange, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lrem, arginfo_class_Redis_lrem, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, ltrim, arginfo_class_Redis_ltrim, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, mget, arginfo_class_Redis_mget, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, migrate, arginfo_class_Redis_migrate, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, move, arginfo_class_Redis_move, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, mset, arginfo_class_Redis_mset, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, msetnx, arginfo_class_Redis_msetnx, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, multi, arginfo_class_Redis_multi, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, object, arginfo_class_Redis_object, ZEND_ACC_PUBLIC)
ZEND_MALIAS(Redis, open, connect, arginfo_class_Redis_open, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
ZEND_ME(Redis, pconnect, arginfo_class_Redis_pconnect, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, persist, arginfo_class_Redis_persist, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, pexpire, arginfo_class_Redis_pexpire, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, pexpireAt, arginfo_class_Redis_pexpireAt, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, pfadd, arginfo_class_Redis_pfadd, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, pfcount, arginfo_class_Redis_pfcount, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, pfmerge, arginfo_class_Redis_pfmerge, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, ping, arginfo_class_Redis_ping, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, pipeline, arginfo_class_Redis_pipeline, ZEND_ACC_PUBLIC)
ZEND_MALIAS(Redis, popen, pconnect, arginfo_class_Redis_popen, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
ZEND_ME(Redis, psetex, arginfo_class_Redis_psetex, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, psubscribe, arginfo_class_Redis_psubscribe, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, pttl, arginfo_class_Redis_pttl, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, publish, arginfo_class_Redis_publish, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, pubsub, arginfo_class_Redis_pubsub, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, punsubscribe, arginfo_class_Redis_punsubscribe, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, rPop, arginfo_class_Redis_rPop, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, randomKey, arginfo_class_Redis_randomKey, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, rawcommand, arginfo_class_Redis_rawcommand, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, rename, arginfo_class_Redis_rename, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, renameNx, arginfo_class_Redis_renameNx, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, reset, arginfo_class_Redis_reset, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, restore, arginfo_class_Redis_restore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, role, arginfo_class_Redis_role, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, rpoplpush, arginfo_class_Redis_rpoplpush, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sAdd, arginfo_class_Redis_sAdd, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sAddArray, arginfo_class_Redis_sAddArray, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sDiff, arginfo_class_Redis_sDiff, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sDiffStore, arginfo_class_Redis_sDiffStore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sInter, arginfo_class_Redis_sInter, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sintercard, arginfo_class_Redis_sintercard, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sInterStore, arginfo_class_Redis_sInterStore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sMembers, arginfo_class_Redis_sMembers, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sMisMember, arginfo_class_Redis_sMisMember, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sMove, arginfo_class_Redis_sMove, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sPop, arginfo_class_Redis_sPop, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sRandMember, arginfo_class_Redis_sRandMember, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sUnion, arginfo_class_Redis_sUnion, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sUnionStore, arginfo_class_Redis_sUnionStore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, save, arginfo_class_Redis_save, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, scan, arginfo_class_Redis_scan, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, scard, arginfo_class_Redis_scard, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, script, arginfo_class_Redis_script, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, select, arginfo_class_Redis_select, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, set, arginfo_class_Redis_set, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, setBit, arginfo_class_Redis_setBit, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, setRange, arginfo_class_Redis_setRange, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, setOption, arginfo_class_Redis_setOption, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, setex, arginfo_class_Redis_setex, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, setnx, arginfo_class_Redis_setnx, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sismember, arginfo_class_Redis_sismember, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, slaveof, arginfo_class_Redis_slaveof, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
ZEND_ME(Redis, replicaof, arginfo_class_Redis_replicaof, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, touch, arginfo_class_Redis_touch, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, slowlog, arginfo_class_Redis_slowlog, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sort, arginfo_class_Redis_sort, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sort_ro, arginfo_class_Redis_sort_ro, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sortAsc, arginfo_class_Redis_sortAsc, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
ZEND_ME(Redis, sortAscAlpha, arginfo_class_Redis_sortAscAlpha, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
ZEND_ME(Redis, sortDesc, arginfo_class_Redis_sortDesc, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
ZEND_ME(Redis, sortDescAlpha, arginfo_class_Redis_sortDescAlpha, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
ZEND_ME(Redis, srem, arginfo_class_Redis_srem, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sscan, arginfo_class_Redis_sscan, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, ssubscribe, arginfo_class_Redis_ssubscribe, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, strlen, arginfo_class_Redis_strlen, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, subscribe, arginfo_class_Redis_subscribe, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sunsubscribe, arginfo_class_Redis_sunsubscribe, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, swapdb, arginfo_class_Redis_swapdb, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, time, arginfo_class_Redis_time, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, ttl, arginfo_class_Redis_ttl, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, type, arginfo_class_Redis_type, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, unlink, arginfo_class_Redis_unlink, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, unsubscribe, arginfo_class_Redis_unsubscribe, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, unwatch, arginfo_class_Redis_unwatch, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, watch, arginfo_class_Redis_watch, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, wait, arginfo_class_Redis_wait, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xack, arginfo_class_Redis_xack, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xadd, arginfo_class_Redis_xadd, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xautoclaim, arginfo_class_Redis_xautoclaim, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xclaim, arginfo_class_Redis_xclaim, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xdel, arginfo_class_Redis_xdel, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xgroup, arginfo_class_Redis_xgroup, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xinfo, arginfo_class_Redis_xinfo, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xlen, arginfo_class_Redis_xlen, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xpending, arginfo_class_Redis_xpending, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xrange, arginfo_class_Redis_xrange, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xread, arginfo_class_Redis_xread, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xreadgroup, arginfo_class_Redis_xreadgroup, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xrevrange, arginfo_class_Redis_xrevrange, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xtrim, arginfo_class_Redis_xtrim, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zAdd, arginfo_class_Redis_zAdd, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zCard, arginfo_class_Redis_zCard, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zCount, arginfo_class_Redis_zCount, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zIncrBy, arginfo_class_Redis_zIncrBy, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zLexCount, arginfo_class_Redis_zLexCount, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zMscore, arginfo_class_Redis_zMscore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zPopMax, arginfo_class_Redis_zPopMax, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zPopMin, arginfo_class_Redis_zPopMin, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRange, arginfo_class_Redis_zRange, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRangeByLex, arginfo_class_Redis_zRangeByLex, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRangeByScore, arginfo_class_Redis_zRangeByScore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zrangestore, arginfo_class_Redis_zrangestore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRandMember, arginfo_class_Redis_zRandMember, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRank, arginfo_class_Redis_zRank, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRem, arginfo_class_Redis_zRem, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRemRangeByLex, arginfo_class_Redis_zRemRangeByLex, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRemRangeByRank, arginfo_class_Redis_zRemRangeByRank, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRemRangeByScore, arginfo_class_Redis_zRemRangeByScore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRevRange, arginfo_class_Redis_zRevRange, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRevRangeByLex, arginfo_class_Redis_zRevRangeByLex, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRevRangeByScore, arginfo_class_Redis_zRevRangeByScore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRevRank, arginfo_class_Redis_zRevRank, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zScore, arginfo_class_Redis_zScore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zdiff, arginfo_class_Redis_zdiff, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zdiffstore, arginfo_class_Redis_zdiffstore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zinter, arginfo_class_Redis_zinter, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zintercard, arginfo_class_Redis_zintercard, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zinterstore, arginfo_class_Redis_zinterstore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zscan, arginfo_class_Redis_zscan, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zunion, arginfo_class_Redis_zunion, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zunionstore, arginfo_class_Redis_zunionstore, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
static const zend_function_entry class_RedisException_methods[] = {
ZEND_FE_END
};
static zend_class_entry *register_class_Redis(void)
{
zend_class_entry ce, *class_entry;
INIT_CLASS_ENTRY(ce, "Redis", class_Redis_methods);
class_entry = zend_register_internal_class_ex(&ce, NULL);
zval const_REDIS_NOT_FOUND_value;
ZVAL_LONG(&const_REDIS_NOT_FOUND_value, REDIS_NOT_FOUND);
zend_string *const_REDIS_NOT_FOUND_name = zend_string_init_interned("REDIS_NOT_FOUND", sizeof("REDIS_NOT_FOUND") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_REDIS_NOT_FOUND_name, &const_REDIS_NOT_FOUND_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_REDIS_NOT_FOUND_name);
zval const_REDIS_STRING_value;
ZVAL_LONG(&const_REDIS_STRING_value, REDIS_STRING);
zend_string *const_REDIS_STRING_name = zend_string_init_interned("REDIS_STRING", sizeof("REDIS_STRING") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_REDIS_STRING_name, &const_REDIS_STRING_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_REDIS_STRING_name);
zval const_REDIS_SET_value;
ZVAL_LONG(&const_REDIS_SET_value, REDIS_SET);
zend_string *const_REDIS_SET_name = zend_string_init_interned("REDIS_SET", sizeof("REDIS_SET") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_REDIS_SET_name, &const_REDIS_SET_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_REDIS_SET_name);
zval const_REDIS_LIST_value;
ZVAL_LONG(&const_REDIS_LIST_value, REDIS_LIST);
zend_string *const_REDIS_LIST_name = zend_string_init_interned("REDIS_LIST", sizeof("REDIS_LIST") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_REDIS_LIST_name, &const_REDIS_LIST_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_REDIS_LIST_name);
zval const_REDIS_ZSET_value;
ZVAL_LONG(&const_REDIS_ZSET_value, REDIS_ZSET);
zend_string *const_REDIS_ZSET_name = zend_string_init_interned("REDIS_ZSET", sizeof("REDIS_ZSET") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_REDIS_ZSET_name, &const_REDIS_ZSET_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_REDIS_ZSET_name);
zval const_REDIS_HASH_value;
ZVAL_LONG(&const_REDIS_HASH_value, REDIS_HASH);
zend_string *const_REDIS_HASH_name = zend_string_init_interned("REDIS_HASH", sizeof("REDIS_HASH") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_REDIS_HASH_name, &const_REDIS_HASH_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_REDIS_HASH_name);
zval const_REDIS_STREAM_value;
ZVAL_LONG(&const_REDIS_STREAM_value, REDIS_STREAM);
zend_string *const_REDIS_STREAM_name = zend_string_init_interned("REDIS_STREAM", sizeof("REDIS_STREAM") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_REDIS_STREAM_name, &const_REDIS_STREAM_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_REDIS_STREAM_name);
zval const_ATOMIC_value;
ZVAL_LONG(&const_ATOMIC_value, ATOMIC);
zend_string *const_ATOMIC_name = zend_string_init_interned("ATOMIC", sizeof("ATOMIC") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_ATOMIC_name, &const_ATOMIC_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_ATOMIC_name);
zval const_MULTI_value;
ZVAL_LONG(&const_MULTI_value, MULTI);
zend_string *const_MULTI_name = zend_string_init_interned("MULTI", sizeof("MULTI") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_MULTI_name, &const_MULTI_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_MULTI_name);
zval const_PIPELINE_value;
ZVAL_LONG(&const_PIPELINE_value, PIPELINE);
zend_string *const_PIPELINE_name = zend_string_init_interned("PIPELINE", sizeof("PIPELINE") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_PIPELINE_name, &const_PIPELINE_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_PIPELINE_name);
zval const_OPT_SERIALIZER_value;
ZVAL_LONG(&const_OPT_SERIALIZER_value, REDIS_OPT_SERIALIZER);
zend_string *const_OPT_SERIALIZER_name = zend_string_init_interned("OPT_SERIALIZER", sizeof("OPT_SERIALIZER") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_SERIALIZER_name, &const_OPT_SERIALIZER_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_SERIALIZER_name);
zval const_OPT_PREFIX_value;
ZVAL_LONG(&const_OPT_PREFIX_value, REDIS_OPT_PREFIX);
zend_string *const_OPT_PREFIX_name = zend_string_init_interned("OPT_PREFIX", sizeof("OPT_PREFIX") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_PREFIX_name, &const_OPT_PREFIX_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_PREFIX_name);
zval const_OPT_READ_TIMEOUT_value;
ZVAL_LONG(&const_OPT_READ_TIMEOUT_value, REDIS_OPT_READ_TIMEOUT);
zend_string *const_OPT_READ_TIMEOUT_name = zend_string_init_interned("OPT_READ_TIMEOUT", sizeof("OPT_READ_TIMEOUT") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_READ_TIMEOUT_name, &const_OPT_READ_TIMEOUT_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_READ_TIMEOUT_name);
zval const_OPT_TCP_KEEPALIVE_value;
ZVAL_LONG(&const_OPT_TCP_KEEPALIVE_value, REDIS_OPT_TCP_KEEPALIVE);
zend_string *const_OPT_TCP_KEEPALIVE_name = zend_string_init_interned("OPT_TCP_KEEPALIVE", sizeof("OPT_TCP_KEEPALIVE") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_TCP_KEEPALIVE_name, &const_OPT_TCP_KEEPALIVE_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_TCP_KEEPALIVE_name);
zval const_OPT_COMPRESSION_value;
ZVAL_LONG(&const_OPT_COMPRESSION_value, REDIS_OPT_COMPRESSION);
zend_string *const_OPT_COMPRESSION_name = zend_string_init_interned("OPT_COMPRESSION", sizeof("OPT_COMPRESSION") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_COMPRESSION_name, &const_OPT_COMPRESSION_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_COMPRESSION_name);
zval const_OPT_REPLY_LITERAL_value;
ZVAL_LONG(&const_OPT_REPLY_LITERAL_value, REDIS_OPT_REPLY_LITERAL);
zend_string *const_OPT_REPLY_LITERAL_name = zend_string_init_interned("OPT_REPLY_LITERAL", sizeof("OPT_REPLY_LITERAL") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_REPLY_LITERAL_name, &const_OPT_REPLY_LITERAL_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_REPLY_LITERAL_name);
zval const_OPT_COMPRESSION_LEVEL_value;
ZVAL_LONG(&const_OPT_COMPRESSION_LEVEL_value, REDIS_OPT_COMPRESSION_LEVEL);
zend_string *const_OPT_COMPRESSION_LEVEL_name = zend_string_init_interned("OPT_COMPRESSION_LEVEL", sizeof("OPT_COMPRESSION_LEVEL") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_COMPRESSION_LEVEL_name, &const_OPT_COMPRESSION_LEVEL_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_COMPRESSION_LEVEL_name);
zval const_OPT_NULL_MULTIBULK_AS_NULL_value;
ZVAL_LONG(&const_OPT_NULL_MULTIBULK_AS_NULL_value, REDIS_OPT_NULL_MBULK_AS_NULL);
zend_string *const_OPT_NULL_MULTIBULK_AS_NULL_name = zend_string_init_interned("OPT_NULL_MULTIBULK_AS_NULL", sizeof("OPT_NULL_MULTIBULK_AS_NULL") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_NULL_MULTIBULK_AS_NULL_name, &const_OPT_NULL_MULTIBULK_AS_NULL_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_NULL_MULTIBULK_AS_NULL_name);
zval const_SERIALIZER_NONE_value;
ZVAL_LONG(&const_SERIALIZER_NONE_value, REDIS_SERIALIZER_NONE);
zend_string *const_SERIALIZER_NONE_name = zend_string_init_interned("SERIALIZER_NONE", sizeof("SERIALIZER_NONE") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_SERIALIZER_NONE_name, &const_SERIALIZER_NONE_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_SERIALIZER_NONE_name);
zval const_SERIALIZER_PHP_value;
ZVAL_LONG(&const_SERIALIZER_PHP_value, REDIS_SERIALIZER_PHP);
zend_string *const_SERIALIZER_PHP_name = zend_string_init_interned("SERIALIZER_PHP", sizeof("SERIALIZER_PHP") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_SERIALIZER_PHP_name, &const_SERIALIZER_PHP_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_SERIALIZER_PHP_name);
#if defined(HAVE_REDIS_IGBINARY)
zval const_SERIALIZER_IGBINARY_value;
ZVAL_LONG(&const_SERIALIZER_IGBINARY_value, REDIS_SERIALIZER_IGBINARY);
zend_string *const_SERIALIZER_IGBINARY_name = zend_string_init_interned("SERIALIZER_IGBINARY", sizeof("SERIALIZER_IGBINARY") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_SERIALIZER_IGBINARY_name, &const_SERIALIZER_IGBINARY_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_SERIALIZER_IGBINARY_name);
#endif
#if defined(HAVE_REDIS_MSGPACK)
zval const_SERIALIZER_MSGPACK_value;
ZVAL_LONG(&const_SERIALIZER_MSGPACK_value, REDIS_SERIALIZER_MSGPACK);
zend_string *const_SERIALIZER_MSGPACK_name = zend_string_init_interned("SERIALIZER_MSGPACK", sizeof("SERIALIZER_MSGPACK") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_SERIALIZER_MSGPACK_name, &const_SERIALIZER_MSGPACK_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_SERIALIZER_MSGPACK_name);
#endif
zval const_SERIALIZER_JSON_value;
ZVAL_LONG(&const_SERIALIZER_JSON_value, REDIS_SERIALIZER_JSON);
zend_string *const_SERIALIZER_JSON_name = zend_string_init_interned("SERIALIZER_JSON", sizeof("SERIALIZER_JSON") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_SERIALIZER_JSON_name, &const_SERIALIZER_JSON_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_SERIALIZER_JSON_name);
zval const_COMPRESSION_NONE_value;
ZVAL_LONG(&const_COMPRESSION_NONE_value, REDIS_COMPRESSION_NONE);
zend_string *const_COMPRESSION_NONE_name = zend_string_init_interned("COMPRESSION_NONE", sizeof("COMPRESSION_NONE") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_COMPRESSION_NONE_name, &const_COMPRESSION_NONE_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_COMPRESSION_NONE_name);
#if defined(HAVE_REDIS_LZF)
zval const_COMPRESSION_LZF_value;
ZVAL_LONG(&const_COMPRESSION_LZF_value, REDIS_COMPRESSION_LZF);
zend_string *const_COMPRESSION_LZF_name = zend_string_init_interned("COMPRESSION_LZF", sizeof("COMPRESSION_LZF") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_COMPRESSION_LZF_name, &const_COMPRESSION_LZF_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_COMPRESSION_LZF_name);
#endif
#if defined(HAVE_REDIS_ZSTD)
zval const_COMPRESSION_ZSTD_value;
ZVAL_LONG(&const_COMPRESSION_ZSTD_value, REDIS_COMPRESSION_ZSTD);
zend_string *const_COMPRESSION_ZSTD_name = zend_string_init_interned("COMPRESSION_ZSTD", sizeof("COMPRESSION_ZSTD") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_COMPRESSION_ZSTD_name, &const_COMPRESSION_ZSTD_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_COMPRESSION_ZSTD_name);
#endif
#if defined(HAVE_REDIS_ZSTD) && defined(ZSTD_CLEVEL_DEFAULT)
zval const_COMPRESSION_ZSTD_DEFAULT_value;
ZVAL_LONG(&const_COMPRESSION_ZSTD_DEFAULT_value, ZSTD_CLEVEL_DEFAULT);
zend_string *const_COMPRESSION_ZSTD_DEFAULT_name = zend_string_init_interned("COMPRESSION_ZSTD_DEFAULT", sizeof("COMPRESSION_ZSTD_DEFAULT") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_COMPRESSION_ZSTD_DEFAULT_name, &const_COMPRESSION_ZSTD_DEFAULT_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_COMPRESSION_ZSTD_DEFAULT_name);
#endif
#if defined(HAVE_REDIS_ZSTD) && !(defined(ZSTD_CLEVEL_DEFAULT))
zval const_COMPRESSION_ZSTD_DEFAULT_value;
ZVAL_LONG(&const_COMPRESSION_ZSTD_DEFAULT_value, 3);
zend_string *const_COMPRESSION_ZSTD_DEFAULT_name = zend_string_init_interned("COMPRESSION_ZSTD_DEFAULT", sizeof("COMPRESSION_ZSTD_DEFAULT") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_COMPRESSION_ZSTD_DEFAULT_name, &const_COMPRESSION_ZSTD_DEFAULT_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_COMPRESSION_ZSTD_DEFAULT_name);
#endif
#if defined(HAVE_REDIS_ZSTD) && defined(ZSTD_CLEVEL_MAX)
zval const_COMPRESSION_ZSTD_MAX_value;
ZVAL_LONG(&const_COMPRESSION_ZSTD_MAX_value, ZSTD_CLEVEL_MAX);
zend_string *const_COMPRESSION_ZSTD_MAX_name = zend_string_init_interned("COMPRESSION_ZSTD_MAX", sizeof("COMPRESSION_ZSTD_MAX") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_COMPRESSION_ZSTD_MAX_name, &const_COMPRESSION_ZSTD_MAX_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_COMPRESSION_ZSTD_MAX_name);
#endif
#if defined(HAVE_REDIS_ZSTD)
zval const_COMPRESSION_ZSTD_MAX_value;
ZVAL_LONG(&const_COMPRESSION_ZSTD_MAX_value, ZSTD_maxCLevel());
zend_string *const_COMPRESSION_ZSTD_MAX_name = zend_string_init_interned("COMPRESSION_ZSTD_MAX", sizeof("COMPRESSION_ZSTD_MAX") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_COMPRESSION_ZSTD_MAX_name, &const_COMPRESSION_ZSTD_MAX_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_COMPRESSION_ZSTD_MAX_name);
#endif
#if defined(HAVE_REDIS_LZ4)
zval const_COMPRESSION_LZ4_value;
ZVAL_LONG(&const_COMPRESSION_LZ4_value, REDIS_COMPRESSION_LZ4);
zend_string *const_COMPRESSION_LZ4_name = zend_string_init_interned("COMPRESSION_LZ4", sizeof("COMPRESSION_LZ4") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_COMPRESSION_LZ4_name, &const_COMPRESSION_LZ4_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_COMPRESSION_LZ4_name);
#endif
zval const_OPT_SCAN_value;
ZVAL_LONG(&const_OPT_SCAN_value, REDIS_OPT_SCAN);
zend_string *const_OPT_SCAN_name = zend_string_init_interned("OPT_SCAN", sizeof("OPT_SCAN") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_SCAN_name, &const_OPT_SCAN_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_SCAN_name);
zval const_SCAN_RETRY_value;
ZVAL_LONG(&const_SCAN_RETRY_value, REDIS_SCAN_RETRY);
zend_string *const_SCAN_RETRY_name = zend_string_init_interned("SCAN_RETRY", sizeof("SCAN_RETRY") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_SCAN_RETRY_name, &const_SCAN_RETRY_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_SCAN_RETRY_name);
zval const_SCAN_NORETRY_value;
ZVAL_LONG(&const_SCAN_NORETRY_value, REDIS_SCAN_NORETRY);
zend_string *const_SCAN_NORETRY_name = zend_string_init_interned("SCAN_NORETRY", sizeof("SCAN_NORETRY") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_SCAN_NORETRY_name, &const_SCAN_NORETRY_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_SCAN_NORETRY_name);
zval const_SCAN_PREFIX_value;
ZVAL_LONG(&const_SCAN_PREFIX_value, REDIS_SCAN_PREFIX);
zend_string *const_SCAN_PREFIX_name = zend_string_init_interned("SCAN_PREFIX", sizeof("SCAN_PREFIX") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_SCAN_PREFIX_name, &const_SCAN_PREFIX_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_SCAN_PREFIX_name);
zval const_SCAN_NOPREFIX_value;
ZVAL_LONG(&const_SCAN_NOPREFIX_value, REDIS_SCAN_NOPREFIX);
zend_string *const_SCAN_NOPREFIX_name = zend_string_init_interned("SCAN_NOPREFIX", sizeof("SCAN_NOPREFIX") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_SCAN_NOPREFIX_name, &const_SCAN_NOPREFIX_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_SCAN_NOPREFIX_name);
zval const_BEFORE_value;
zend_string *const_BEFORE_value_str = zend_string_init("before", strlen("before"), 1);
ZVAL_STR(&const_BEFORE_value, const_BEFORE_value_str);
zend_string *const_BEFORE_name = zend_string_init_interned("BEFORE", sizeof("BEFORE") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_BEFORE_name, &const_BEFORE_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_BEFORE_name);
zval const_AFTER_value;
zend_string *const_AFTER_value_str = zend_string_init("after", strlen("after"), 1);
ZVAL_STR(&const_AFTER_value, const_AFTER_value_str);
zend_string *const_AFTER_name = zend_string_init_interned("AFTER", sizeof("AFTER") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_AFTER_name, &const_AFTER_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_AFTER_name);
zval const_LEFT_value;
zend_string *const_LEFT_value_str = zend_string_init("left", strlen("left"), 1);
ZVAL_STR(&const_LEFT_value, const_LEFT_value_str);
zend_string *const_LEFT_name = zend_string_init_interned("LEFT", sizeof("LEFT") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_LEFT_name, &const_LEFT_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_LEFT_name);
zval const_RIGHT_value;
zend_string *const_RIGHT_value_str = zend_string_init("right", strlen("right"), 1);
ZVAL_STR(&const_RIGHT_value, const_RIGHT_value_str);
zend_string *const_RIGHT_name = zend_string_init_interned("RIGHT", sizeof("RIGHT") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_RIGHT_name, &const_RIGHT_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_RIGHT_name);
zval const_OPT_MAX_RETRIES_value;
ZVAL_LONG(&const_OPT_MAX_RETRIES_value, REDIS_OPT_MAX_RETRIES);
zend_string *const_OPT_MAX_RETRIES_name = zend_string_init_interned("OPT_MAX_RETRIES", sizeof("OPT_MAX_RETRIES") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_MAX_RETRIES_name, &const_OPT_MAX_RETRIES_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_MAX_RETRIES_name);
zval const_OPT_BACKOFF_ALGORITHM_value;
ZVAL_LONG(&const_OPT_BACKOFF_ALGORITHM_value, REDIS_OPT_BACKOFF_ALGORITHM);
zend_string *const_OPT_BACKOFF_ALGORITHM_name = zend_string_init_interned("OPT_BACKOFF_ALGORITHM", sizeof("OPT_BACKOFF_ALGORITHM") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_BACKOFF_ALGORITHM_name, &const_OPT_BACKOFF_ALGORITHM_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_BACKOFF_ALGORITHM_name);
zval const_BACKOFF_ALGORITHM_DEFAULT_value;
ZVAL_LONG(&const_BACKOFF_ALGORITHM_DEFAULT_value, REDIS_BACKOFF_ALGORITHM_DEFAULT);
zend_string *const_BACKOFF_ALGORITHM_DEFAULT_name = zend_string_init_interned("BACKOFF_ALGORITHM_DEFAULT", sizeof("BACKOFF_ALGORITHM_DEFAULT") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_BACKOFF_ALGORITHM_DEFAULT_name, &const_BACKOFF_ALGORITHM_DEFAULT_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_BACKOFF_ALGORITHM_DEFAULT_name);
zval const_BACKOFF_ALGORITHM_CONSTANT_value;
ZVAL_LONG(&const_BACKOFF_ALGORITHM_CONSTANT_value, REDIS_BACKOFF_ALGORITHM_CONSTANT);
zend_string *const_BACKOFF_ALGORITHM_CONSTANT_name = zend_string_init_interned("BACKOFF_ALGORITHM_CONSTANT", sizeof("BACKOFF_ALGORITHM_CONSTANT") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_BACKOFF_ALGORITHM_CONSTANT_name, &const_BACKOFF_ALGORITHM_CONSTANT_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_BACKOFF_ALGORITHM_CONSTANT_name);
zval const_BACKOFF_ALGORITHM_UNIFORM_value;
ZVAL_LONG(&const_BACKOFF_ALGORITHM_UNIFORM_value, REDIS_BACKOFF_ALGORITHM_UNIFORM);
zend_string *const_BACKOFF_ALGORITHM_UNIFORM_name = zend_string_init_interned("BACKOFF_ALGORITHM_UNIFORM", sizeof("BACKOFF_ALGORITHM_UNIFORM") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_BACKOFF_ALGORITHM_UNIFORM_name, &const_BACKOFF_ALGORITHM_UNIFORM_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_BACKOFF_ALGORITHM_UNIFORM_name);
zval const_BACKOFF_ALGORITHM_EXPONENTIAL_value;
ZVAL_LONG(&const_BACKOFF_ALGORITHM_EXPONENTIAL_value, REDIS_BACKOFF_ALGORITHM_EXPONENTIAL);
zend_string *const_BACKOFF_ALGORITHM_EXPONENTIAL_name = zend_string_init_interned("BACKOFF_ALGORITHM_EXPONENTIAL", sizeof("BACKOFF_ALGORITHM_EXPONENTIAL") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_BACKOFF_ALGORITHM_EXPONENTIAL_name, &const_BACKOFF_ALGORITHM_EXPONENTIAL_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_BACKOFF_ALGORITHM_EXPONENTIAL_name);
zval const_BACKOFF_ALGORITHM_FULL_JITTER_value;
ZVAL_LONG(&const_BACKOFF_ALGORITHM_FULL_JITTER_value, REDIS_BACKOFF_ALGORITHM_FULL_JITTER);
zend_string *const_BACKOFF_ALGORITHM_FULL_JITTER_name = zend_string_init_interned("BACKOFF_ALGORITHM_FULL_JITTER", sizeof("BACKOFF_ALGORITHM_FULL_JITTER") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_BACKOFF_ALGORITHM_FULL_JITTER_name, &const_BACKOFF_ALGORITHM_FULL_JITTER_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_BACKOFF_ALGORITHM_FULL_JITTER_name);
zval const_BACKOFF_ALGORITHM_EQUAL_JITTER_value;
ZVAL_LONG(&const_BACKOFF_ALGORITHM_EQUAL_JITTER_value, REDIS_BACKOFF_ALGORITHM_EQUAL_JITTER);
zend_string *const_BACKOFF_ALGORITHM_EQUAL_JITTER_name = zend_string_init_interned("BACKOFF_ALGORITHM_EQUAL_JITTER", sizeof("BACKOFF_ALGORITHM_EQUAL_JITTER") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_BACKOFF_ALGORITHM_EQUAL_JITTER_name, &const_BACKOFF_ALGORITHM_EQUAL_JITTER_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_BACKOFF_ALGORITHM_EQUAL_JITTER_name);
zval const_BACKOFF_ALGORITHM_DECORRELATED_JITTER_value;
ZVAL_LONG(&const_BACKOFF_ALGORITHM_DECORRELATED_JITTER_value, REDIS_BACKOFF_ALGORITHM_DECORRELATED_JITTER);
zend_string *const_BACKOFF_ALGORITHM_DECORRELATED_JITTER_name = zend_string_init_interned("BACKOFF_ALGORITHM_DECORRELATED_JITTER", sizeof("BACKOFF_ALGORITHM_DECORRELATED_JITTER") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_BACKOFF_ALGORITHM_DECORRELATED_JITTER_name, &const_BACKOFF_ALGORITHM_DECORRELATED_JITTER_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_BACKOFF_ALGORITHM_DECORRELATED_JITTER_name);
zval const_OPT_BACKOFF_BASE_value;
ZVAL_LONG(&const_OPT_BACKOFF_BASE_value, REDIS_OPT_BACKOFF_BASE);
zend_string *const_OPT_BACKOFF_BASE_name = zend_string_init_interned("OPT_BACKOFF_BASE", sizeof("OPT_BACKOFF_BASE") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_BACKOFF_BASE_name, &const_OPT_BACKOFF_BASE_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_BACKOFF_BASE_name);
zval const_OPT_BACKOFF_CAP_value;
ZVAL_LONG(&const_OPT_BACKOFF_CAP_value, REDIS_OPT_BACKOFF_CAP);
zend_string *const_OPT_BACKOFF_CAP_name = zend_string_init_interned("OPT_BACKOFF_CAP", sizeof("OPT_BACKOFF_CAP") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_BACKOFF_CAP_name, &const_OPT_BACKOFF_CAP_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_BACKOFF_CAP_name);
#if (PHP_VERSION_ID >= 80200)
zend_add_parameter_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "auth", sizeof("auth") - 1), 0, ZSTR_KNOWN(ZEND_STR_SENSITIVEPARAMETER), 0);
zend_add_parameter_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "migrate", sizeof("migrate") - 1), 7, ZSTR_KNOWN(ZEND_STR_SENSITIVEPARAMETER), 0);
#endif
return class_entry;
}
static zend_class_entry *register_class_RedisException(zend_class_entry *class_entry_RuntimeException)
{
zend_class_entry ce, *class_entry;
INIT_CLASS_ENTRY(ce, "RedisException", class_RedisException_methods);
class_entry = zend_register_internal_class_ex(&ce, class_entry_RuntimeException);
return class_entry;
}
redis-6.0.2/redis_legacy_arginfo.h 0000644 0001750 0000012 00000225022 14515245367 017733 0 ustar pyatsukhnenko wheel /* This is a generated file, edit the .stub.php file instead.
* Stub hash: 8cf0ecc2f5a43c6ede68d537a76faa23cb912d96 */
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___construct, 0, 0, 0)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___destruct, 0, 0, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis__compress, 0, 0, 1)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis__uncompress arginfo_class_Redis__compress
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis__prefix, 0, 0, 1)
ZEND_ARG_INFO(0, key)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis__serialize arginfo_class_Redis__compress
#define arginfo_class_Redis__unserialize arginfo_class_Redis__compress
#define arginfo_class_Redis__pack arginfo_class_Redis__compress
#define arginfo_class_Redis__unpack arginfo_class_Redis__compress
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_acl, 0, 0, 1)
ZEND_ARG_INFO(0, subcmd)
ZEND_ARG_VARIADIC_INFO(0, args)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_append, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_auth, 0, 0, 1)
ZEND_ARG_INFO(0, credentials)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_bgSave arginfo_class_Redis___destruct
#define arginfo_class_Redis_bgrewriteaof arginfo_class_Redis___destruct
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_bitcount, 0, 0, 1)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, start)
ZEND_ARG_INFO(0, end)
ZEND_ARG_INFO(0, bybit)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_bitop, 0, 0, 3)
ZEND_ARG_INFO(0, operation)
ZEND_ARG_INFO(0, deskey)
ZEND_ARG_INFO(0, srckey)
ZEND_ARG_VARIADIC_INFO(0, other_keys)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_bitpos, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, bit)
ZEND_ARG_INFO(0, start)
ZEND_ARG_INFO(0, end)
ZEND_ARG_INFO(0, bybit)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_blPop, 0, 0, 2)
ZEND_ARG_INFO(0, key_or_keys)
ZEND_ARG_INFO(0, timeout_or_key)
ZEND_ARG_VARIADIC_INFO(0, extra_args)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_brPop arginfo_class_Redis_blPop
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_brpoplpush, 0, 0, 3)
ZEND_ARG_INFO(0, src)
ZEND_ARG_INFO(0, dst)
ZEND_ARG_INFO(0, timeout)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_bzPopMax, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, timeout_or_key)
ZEND_ARG_VARIADIC_INFO(0, extra_args)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_bzPopMin arginfo_class_Redis_bzPopMax
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_bzmpop, 0, 0, 3)
ZEND_ARG_INFO(0, timeout)
ZEND_ARG_INFO(0, keys)
ZEND_ARG_INFO(0, from)
ZEND_ARG_INFO(0, count)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_zmpop, 0, 0, 2)
ZEND_ARG_INFO(0, keys)
ZEND_ARG_INFO(0, from)
ZEND_ARG_INFO(0, count)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_blmpop arginfo_class_Redis_bzmpop
#define arginfo_class_Redis_lmpop arginfo_class_Redis_zmpop
#define arginfo_class_Redis_clearLastError arginfo_class_Redis___destruct
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_client, 0, 0, 1)
ZEND_ARG_INFO(0, opt)
ZEND_ARG_VARIADIC_INFO(0, args)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_close arginfo_class_Redis___destruct
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_command, 0, 0, 0)
ZEND_ARG_INFO(0, opt)
ZEND_ARG_VARIADIC_INFO(0, args)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_config, 0, 0, 1)
ZEND_ARG_INFO(0, operation)
ZEND_ARG_INFO(0, key_or_settings)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_connect, 0, 0, 1)
ZEND_ARG_INFO(0, host)
ZEND_ARG_INFO(0, port)
ZEND_ARG_INFO(0, timeout)
ZEND_ARG_INFO(0, persistent_id)
ZEND_ARG_INFO(0, retry_interval)
ZEND_ARG_INFO(0, read_timeout)
ZEND_ARG_INFO(0, context)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_copy, 0, 0, 2)
ZEND_ARG_INFO(0, src)
ZEND_ARG_INFO(0, dst)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_dbSize arginfo_class_Redis___destruct
#define arginfo_class_Redis_debug arginfo_class_Redis__prefix
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_decr, 0, 0, 1)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, by)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_decrBy arginfo_class_Redis_append
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_del, 0, 0, 1)
ZEND_ARG_INFO(0, key)
ZEND_ARG_VARIADIC_INFO(0, other_keys)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_delete arginfo_class_Redis_del
#define arginfo_class_Redis_discard arginfo_class_Redis___destruct
#define arginfo_class_Redis_dump arginfo_class_Redis__prefix
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_echo, 0, 0, 1)
ZEND_ARG_INFO(0, str)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_eval, 0, 0, 1)
ZEND_ARG_INFO(0, script)
ZEND_ARG_INFO(0, args)
ZEND_ARG_INFO(0, num_keys)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_eval_ro, 0, 0, 1)
ZEND_ARG_INFO(0, script_sha)
ZEND_ARG_INFO(0, args)
ZEND_ARG_INFO(0, num_keys)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_evalsha, 0, 0, 1)
ZEND_ARG_INFO(0, sha1)
ZEND_ARG_INFO(0, args)
ZEND_ARG_INFO(0, num_keys)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_evalsha_ro arginfo_class_Redis_evalsha
#define arginfo_class_Redis_exec arginfo_class_Redis___destruct
#define arginfo_class_Redis_exists arginfo_class_Redis_del
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_expire, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, timeout)
ZEND_ARG_INFO(0, mode)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_expireAt, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, timestamp)
ZEND_ARG_INFO(0, mode)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_failover, 0, 0, 0)
ZEND_ARG_INFO(0, to)
ZEND_ARG_INFO(0, abort)
ZEND_ARG_INFO(0, timeout)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_expiretime arginfo_class_Redis__prefix
#define arginfo_class_Redis_pexpiretime arginfo_class_Redis__prefix
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_fcall, 0, 0, 1)
ZEND_ARG_INFO(0, fn)
ZEND_ARG_INFO(0, keys)
ZEND_ARG_INFO(0, args)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_fcall_ro arginfo_class_Redis_fcall
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_flushAll, 0, 0, 0)
ZEND_ARG_INFO(0, sync)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_flushDB arginfo_class_Redis_flushAll
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_function, 0, 0, 1)
ZEND_ARG_INFO(0, operation)
ZEND_ARG_VARIADIC_INFO(0, args)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_geoadd, 0, 0, 4)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, lng)
ZEND_ARG_INFO(0, lat)
ZEND_ARG_INFO(0, member)
ZEND_ARG_VARIADIC_INFO(0, other_triples_and_options)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_geodist, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, src)
ZEND_ARG_INFO(0, dst)
ZEND_ARG_INFO(0, unit)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_geohash, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, member)
ZEND_ARG_VARIADIC_INFO(0, other_members)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_geopos arginfo_class_Redis_geohash
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_georadius, 0, 0, 5)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, lng)
ZEND_ARG_INFO(0, lat)
ZEND_ARG_INFO(0, radius)
ZEND_ARG_INFO(0, unit)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_georadius_ro arginfo_class_Redis_georadius
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_georadiusbymember, 0, 0, 4)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, member)
ZEND_ARG_INFO(0, radius)
ZEND_ARG_INFO(0, unit)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_georadiusbymember_ro arginfo_class_Redis_georadiusbymember
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_geosearch, 0, 0, 4)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, position)
ZEND_ARG_INFO(0, shape)
ZEND_ARG_INFO(0, unit)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_geosearchstore, 0, 0, 5)
ZEND_ARG_INFO(0, dst)
ZEND_ARG_INFO(0, src)
ZEND_ARG_INFO(0, position)
ZEND_ARG_INFO(0, shape)
ZEND_ARG_INFO(0, unit)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_get arginfo_class_Redis__prefix
#define arginfo_class_Redis_getAuth arginfo_class_Redis___destruct
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_getBit, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, idx)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_getEx, 0, 0, 1)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_getDBNum arginfo_class_Redis___destruct
#define arginfo_class_Redis_getDel arginfo_class_Redis__prefix
#define arginfo_class_Redis_getHost arginfo_class_Redis___destruct
#define arginfo_class_Redis_getLastError arginfo_class_Redis___destruct
#define arginfo_class_Redis_getMode arginfo_class_Redis___destruct
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_getOption, 0, 0, 1)
ZEND_ARG_INFO(0, option)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_getPersistentID arginfo_class_Redis___destruct
#define arginfo_class_Redis_getPort arginfo_class_Redis___destruct
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_getRange, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, start)
ZEND_ARG_INFO(0, end)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_lcs, 0, 0, 2)
ZEND_ARG_INFO(0, key1)
ZEND_ARG_INFO(0, key2)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_getReadTimeout arginfo_class_Redis___destruct
#define arginfo_class_Redis_getset arginfo_class_Redis_append
#define arginfo_class_Redis_getTimeout arginfo_class_Redis___destruct
#define arginfo_class_Redis_getTransferredBytes arginfo_class_Redis___destruct
#define arginfo_class_Redis_clearTransferredBytes arginfo_class_Redis___destruct
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_hDel, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, field)
ZEND_ARG_VARIADIC_INFO(0, other_fields)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_hExists, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, field)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_hGet, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, member)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_hGetAll arginfo_class_Redis__prefix
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_hIncrBy, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, field)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_hIncrByFloat arginfo_class_Redis_hIncrBy
#define arginfo_class_Redis_hKeys arginfo_class_Redis__prefix
#define arginfo_class_Redis_hLen arginfo_class_Redis__prefix
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_hMget, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, fields)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_hMset, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, fieldvals)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_hRandField arginfo_class_Redis_getEx
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_hSet, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, member)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_hSetNx arginfo_class_Redis_hIncrBy
#define arginfo_class_Redis_hStrLen arginfo_class_Redis_hExists
#define arginfo_class_Redis_hVals arginfo_class_Redis__prefix
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_hscan, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(1, iterator)
ZEND_ARG_INFO(0, pattern)
ZEND_ARG_INFO(0, count)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_incr arginfo_class_Redis_decr
#define arginfo_class_Redis_incrBy arginfo_class_Redis_append
#define arginfo_class_Redis_incrByFloat arginfo_class_Redis_append
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_info, 0, 0, 0)
ZEND_ARG_VARIADIC_INFO(0, sections)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_isConnected arginfo_class_Redis___destruct
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_keys, 0, 0, 1)
ZEND_ARG_INFO(0, pattern)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_lInsert, 0, 0, 4)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, pos)
ZEND_ARG_INFO(0, pivot)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_lLen arginfo_class_Redis__prefix
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_lMove, 0, 0, 4)
ZEND_ARG_INFO(0, src)
ZEND_ARG_INFO(0, dst)
ZEND_ARG_INFO(0, wherefrom)
ZEND_ARG_INFO(0, whereto)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_blmove, 0, 0, 5)
ZEND_ARG_INFO(0, src)
ZEND_ARG_INFO(0, dst)
ZEND_ARG_INFO(0, wherefrom)
ZEND_ARG_INFO(0, whereto)
ZEND_ARG_INFO(0, timeout)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_lPop, 0, 0, 1)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, count)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_lPos, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_lPush, 0, 0, 1)
ZEND_ARG_INFO(0, key)
ZEND_ARG_VARIADIC_INFO(0, elements)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_rPush arginfo_class_Redis_lPush
#define arginfo_class_Redis_lPushx arginfo_class_Redis_append
#define arginfo_class_Redis_rPushx arginfo_class_Redis_append
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_lSet, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, index)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_lastSave arginfo_class_Redis___destruct
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_lindex, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, index)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_lrange arginfo_class_Redis_getRange
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_lrem, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, count)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_ltrim arginfo_class_Redis_getRange
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_mget, 0, 0, 1)
ZEND_ARG_INFO(0, keys)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_migrate, 0, 0, 5)
ZEND_ARG_INFO(0, host)
ZEND_ARG_INFO(0, port)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, dstdb)
ZEND_ARG_INFO(0, timeout)
ZEND_ARG_INFO(0, copy)
ZEND_ARG_INFO(0, replace)
ZEND_ARG_INFO(0, credentials)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_move arginfo_class_Redis_lindex
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_mset, 0, 0, 1)
ZEND_ARG_INFO(0, key_values)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_msetnx arginfo_class_Redis_mset
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_multi, 0, 0, 0)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_object, 0, 0, 2)
ZEND_ARG_INFO(0, subcommand)
ZEND_ARG_INFO(0, key)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_open arginfo_class_Redis_connect
#define arginfo_class_Redis_pconnect arginfo_class_Redis_connect
#define arginfo_class_Redis_persist arginfo_class_Redis__prefix
#define arginfo_class_Redis_pexpire arginfo_class_Redis_expire
#define arginfo_class_Redis_pexpireAt arginfo_class_Redis_expireAt
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_pfadd, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, elements)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_pfcount, 0, 0, 1)
ZEND_ARG_INFO(0, key_or_keys)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_pfmerge, 0, 0, 2)
ZEND_ARG_INFO(0, dst)
ZEND_ARG_INFO(0, srckeys)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_ping, 0, 0, 0)
ZEND_ARG_INFO(0, message)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_pipeline arginfo_class_Redis___destruct
#define arginfo_class_Redis_popen arginfo_class_Redis_connect
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_psetex, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, expire)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_psubscribe, 0, 0, 2)
ZEND_ARG_INFO(0, patterns)
ZEND_ARG_INFO(0, cb)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_pttl arginfo_class_Redis__prefix
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_publish, 0, 0, 2)
ZEND_ARG_INFO(0, channel)
ZEND_ARG_INFO(0, message)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_pubsub, 0, 0, 1)
ZEND_ARG_INFO(0, command)
ZEND_ARG_INFO(0, arg)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_punsubscribe, 0, 0, 1)
ZEND_ARG_INFO(0, patterns)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_rPop arginfo_class_Redis_lPop
#define arginfo_class_Redis_randomKey arginfo_class_Redis___destruct
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_rawcommand, 0, 0, 1)
ZEND_ARG_INFO(0, command)
ZEND_ARG_VARIADIC_INFO(0, args)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_rename, 0, 0, 2)
ZEND_ARG_INFO(0, old_name)
ZEND_ARG_INFO(0, new_name)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_renameNx, 0, 0, 2)
ZEND_ARG_INFO(0, key_src)
ZEND_ARG_INFO(0, key_dst)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_reset arginfo_class_Redis___destruct
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_restore, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, ttl)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_role arginfo_class_Redis___destruct
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_rpoplpush, 0, 0, 2)
ZEND_ARG_INFO(0, srckey)
ZEND_ARG_INFO(0, dstkey)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_sAdd, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_VARIADIC_INFO(0, other_values)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_sAddArray, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, values)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_sDiff arginfo_class_Redis_del
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_sDiffStore, 0, 0, 2)
ZEND_ARG_INFO(0, dst)
ZEND_ARG_INFO(0, key)
ZEND_ARG_VARIADIC_INFO(0, other_keys)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_sInter arginfo_class_Redis_del
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_sintercard, 0, 0, 1)
ZEND_ARG_INFO(0, keys)
ZEND_ARG_INFO(0, limit)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_sInterStore arginfo_class_Redis_del
#define arginfo_class_Redis_sMembers arginfo_class_Redis__prefix
#define arginfo_class_Redis_sMisMember arginfo_class_Redis_geohash
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_sMove, 0, 0, 3)
ZEND_ARG_INFO(0, src)
ZEND_ARG_INFO(0, dst)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_sPop arginfo_class_Redis_lPop
#define arginfo_class_Redis_sRandMember arginfo_class_Redis_lPop
#define arginfo_class_Redis_sUnion arginfo_class_Redis_del
#define arginfo_class_Redis_sUnionStore arginfo_class_Redis_sDiffStore
#define arginfo_class_Redis_save arginfo_class_Redis___destruct
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_scan, 0, 0, 1)
ZEND_ARG_INFO(1, iterator)
ZEND_ARG_INFO(0, pattern)
ZEND_ARG_INFO(0, count)
ZEND_ARG_INFO(0, type)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_scard arginfo_class_Redis__prefix
#define arginfo_class_Redis_script arginfo_class_Redis_rawcommand
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_select, 0, 0, 1)
ZEND_ARG_INFO(0, db)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_set arginfo_class_Redis_lPos
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_setBit, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, idx)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_setRange arginfo_class_Redis_lSet
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_setOption, 0, 0, 2)
ZEND_ARG_INFO(0, option)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_setex arginfo_class_Redis_psetex
#define arginfo_class_Redis_setnx arginfo_class_Redis_append
#define arginfo_class_Redis_sismember arginfo_class_Redis_append
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_slaveof, 0, 0, 0)
ZEND_ARG_INFO(0, host)
ZEND_ARG_INFO(0, port)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_replicaof arginfo_class_Redis_slaveof
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_touch, 0, 0, 1)
ZEND_ARG_INFO(0, key_or_array)
ZEND_ARG_VARIADIC_INFO(0, more_keys)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_slowlog, 0, 0, 1)
ZEND_ARG_INFO(0, operation)
ZEND_ARG_INFO(0, length)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_sort arginfo_class_Redis_getEx
#define arginfo_class_Redis_sort_ro arginfo_class_Redis_getEx
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_sortAsc, 0, 0, 1)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, pattern)
ZEND_ARG_INFO(0, get)
ZEND_ARG_INFO(0, offset)
ZEND_ARG_INFO(0, count)
ZEND_ARG_INFO(0, store)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_sortAscAlpha arginfo_class_Redis_sortAsc
#define arginfo_class_Redis_sortDesc arginfo_class_Redis_sortAsc
#define arginfo_class_Redis_sortDescAlpha arginfo_class_Redis_sortAsc
#define arginfo_class_Redis_srem arginfo_class_Redis_sAdd
#define arginfo_class_Redis_sscan arginfo_class_Redis_hscan
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_ssubscribe, 0, 0, 2)
ZEND_ARG_INFO(0, channels)
ZEND_ARG_INFO(0, cb)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_strlen arginfo_class_Redis__prefix
#define arginfo_class_Redis_subscribe arginfo_class_Redis_ssubscribe
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_sunsubscribe, 0, 0, 1)
ZEND_ARG_INFO(0, channels)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_swapdb, 0, 0, 2)
ZEND_ARG_INFO(0, src)
ZEND_ARG_INFO(0, dst)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_time arginfo_class_Redis___destruct
#define arginfo_class_Redis_ttl arginfo_class_Redis__prefix
#define arginfo_class_Redis_type arginfo_class_Redis__prefix
#define arginfo_class_Redis_unlink arginfo_class_Redis_del
#define arginfo_class_Redis_unsubscribe arginfo_class_Redis_sunsubscribe
#define arginfo_class_Redis_unwatch arginfo_class_Redis___destruct
#define arginfo_class_Redis_watch arginfo_class_Redis_del
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_wait, 0, 0, 2)
ZEND_ARG_INFO(0, numreplicas)
ZEND_ARG_INFO(0, timeout)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_xack, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, group)
ZEND_ARG_INFO(0, ids)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_xadd, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, id)
ZEND_ARG_INFO(0, values)
ZEND_ARG_INFO(0, maxlen)
ZEND_ARG_INFO(0, approx)
ZEND_ARG_INFO(0, nomkstream)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_xautoclaim, 0, 0, 5)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, group)
ZEND_ARG_INFO(0, consumer)
ZEND_ARG_INFO(0, min_idle)
ZEND_ARG_INFO(0, start)
ZEND_ARG_INFO(0, count)
ZEND_ARG_INFO(0, justid)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_xclaim, 0, 0, 6)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, group)
ZEND_ARG_INFO(0, consumer)
ZEND_ARG_INFO(0, min_idle)
ZEND_ARG_INFO(0, ids)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_xdel, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, ids)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_xgroup, 0, 0, 1)
ZEND_ARG_INFO(0, operation)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, group)
ZEND_ARG_INFO(0, id_or_consumer)
ZEND_ARG_INFO(0, mkstream)
ZEND_ARG_INFO(0, entries_read)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_xinfo, 0, 0, 1)
ZEND_ARG_INFO(0, operation)
ZEND_ARG_INFO(0, arg1)
ZEND_ARG_INFO(0, arg2)
ZEND_ARG_INFO(0, count)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_xlen arginfo_class_Redis__prefix
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_xpending, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, group)
ZEND_ARG_INFO(0, start)
ZEND_ARG_INFO(0, end)
ZEND_ARG_INFO(0, count)
ZEND_ARG_INFO(0, consumer)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_xrange, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, start)
ZEND_ARG_INFO(0, end)
ZEND_ARG_INFO(0, count)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_xread, 0, 0, 1)
ZEND_ARG_INFO(0, streams)
ZEND_ARG_INFO(0, count)
ZEND_ARG_INFO(0, block)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_xreadgroup, 0, 0, 3)
ZEND_ARG_INFO(0, group)
ZEND_ARG_INFO(0, consumer)
ZEND_ARG_INFO(0, streams)
ZEND_ARG_INFO(0, count)
ZEND_ARG_INFO(0, block)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_xrevrange, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, end)
ZEND_ARG_INFO(0, start)
ZEND_ARG_INFO(0, count)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_xtrim, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, threshold)
ZEND_ARG_INFO(0, approx)
ZEND_ARG_INFO(0, minid)
ZEND_ARG_INFO(0, limit)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_zAdd, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, score_or_options)
ZEND_ARG_VARIADIC_INFO(0, more_scores_and_mems)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_zCard arginfo_class_Redis__prefix
#define arginfo_class_Redis_zCount arginfo_class_Redis_getRange
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_zIncrBy, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, member)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_zLexCount, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, min)
ZEND_ARG_INFO(0, max)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_zMscore arginfo_class_Redis_geohash
#define arginfo_class_Redis_zPopMax arginfo_class_Redis_lPop
#define arginfo_class_Redis_zPopMin arginfo_class_Redis_lPop
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_zRange, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, start)
ZEND_ARG_INFO(0, end)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_zRangeByLex, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, min)
ZEND_ARG_INFO(0, max)
ZEND_ARG_INFO(0, offset)
ZEND_ARG_INFO(0, count)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_zRangeByScore arginfo_class_Redis_zRange
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_zrangestore, 0, 0, 4)
ZEND_ARG_INFO(0, dstkey)
ZEND_ARG_INFO(0, srckey)
ZEND_ARG_INFO(0, start)
ZEND_ARG_INFO(0, end)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_zRandMember arginfo_class_Redis_getEx
#define arginfo_class_Redis_zRank arginfo_class_Redis_hGet
#define arginfo_class_Redis_zRem arginfo_class_Redis_geohash
#define arginfo_class_Redis_zRemRangeByLex arginfo_class_Redis_zLexCount
#define arginfo_class_Redis_zRemRangeByRank arginfo_class_Redis_getRange
#define arginfo_class_Redis_zRemRangeByScore arginfo_class_Redis_getRange
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_zRevRange, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, start)
ZEND_ARG_INFO(0, end)
ZEND_ARG_INFO(0, scores)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_zRevRangeByLex, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, max)
ZEND_ARG_INFO(0, min)
ZEND_ARG_INFO(0, offset)
ZEND_ARG_INFO(0, count)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_zRevRangeByScore, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, max)
ZEND_ARG_INFO(0, min)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_zRevRank arginfo_class_Redis_hGet
#define arginfo_class_Redis_zScore arginfo_class_Redis_hGet
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_zdiff, 0, 0, 1)
ZEND_ARG_INFO(0, keys)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_zdiffstore, 0, 0, 2)
ZEND_ARG_INFO(0, dst)
ZEND_ARG_INFO(0, keys)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_zinter, 0, 0, 1)
ZEND_ARG_INFO(0, keys)
ZEND_ARG_INFO(0, weights)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_zintercard arginfo_class_Redis_sintercard
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_zinterstore, 0, 0, 2)
ZEND_ARG_INFO(0, dst)
ZEND_ARG_INFO(0, keys)
ZEND_ARG_INFO(0, weights)
ZEND_ARG_INFO(0, aggregate)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_zscan arginfo_class_Redis_hscan
#define arginfo_class_Redis_zunion arginfo_class_Redis_zinter
#define arginfo_class_Redis_zunionstore arginfo_class_Redis_zinterstore
ZEND_METHOD(Redis, __construct);
ZEND_METHOD(Redis, __destruct);
ZEND_METHOD(Redis, _compress);
ZEND_METHOD(Redis, _uncompress);
ZEND_METHOD(Redis, _prefix);
ZEND_METHOD(Redis, _serialize);
ZEND_METHOD(Redis, _unserialize);
ZEND_METHOD(Redis, _pack);
ZEND_METHOD(Redis, _unpack);
ZEND_METHOD(Redis, acl);
ZEND_METHOD(Redis, append);
ZEND_METHOD(Redis, auth);
ZEND_METHOD(Redis, bgSave);
ZEND_METHOD(Redis, bgrewriteaof);
ZEND_METHOD(Redis, bitcount);
ZEND_METHOD(Redis, bitop);
ZEND_METHOD(Redis, bitpos);
ZEND_METHOD(Redis, blPop);
ZEND_METHOD(Redis, brPop);
ZEND_METHOD(Redis, brpoplpush);
ZEND_METHOD(Redis, bzPopMax);
ZEND_METHOD(Redis, bzPopMin);
ZEND_METHOD(Redis, bzmpop);
ZEND_METHOD(Redis, zmpop);
ZEND_METHOD(Redis, blmpop);
ZEND_METHOD(Redis, lmpop);
ZEND_METHOD(Redis, clearLastError);
ZEND_METHOD(Redis, client);
ZEND_METHOD(Redis, close);
ZEND_METHOD(Redis, command);
ZEND_METHOD(Redis, config);
ZEND_METHOD(Redis, connect);
ZEND_METHOD(Redis, copy);
ZEND_METHOD(Redis, dbSize);
ZEND_METHOD(Redis, debug);
ZEND_METHOD(Redis, decr);
ZEND_METHOD(Redis, decrBy);
ZEND_METHOD(Redis, del);
ZEND_METHOD(Redis, discard);
ZEND_METHOD(Redis, dump);
ZEND_METHOD(Redis, echo);
ZEND_METHOD(Redis, eval);
ZEND_METHOD(Redis, eval_ro);
ZEND_METHOD(Redis, evalsha);
ZEND_METHOD(Redis, evalsha_ro);
ZEND_METHOD(Redis, exec);
ZEND_METHOD(Redis, exists);
ZEND_METHOD(Redis, expire);
ZEND_METHOD(Redis, expireAt);
ZEND_METHOD(Redis, failover);
ZEND_METHOD(Redis, expiretime);
ZEND_METHOD(Redis, pexpiretime);
ZEND_METHOD(Redis, fcall);
ZEND_METHOD(Redis, fcall_ro);
ZEND_METHOD(Redis, flushAll);
ZEND_METHOD(Redis, flushDB);
ZEND_METHOD(Redis, function);
ZEND_METHOD(Redis, geoadd);
ZEND_METHOD(Redis, geodist);
ZEND_METHOD(Redis, geohash);
ZEND_METHOD(Redis, geopos);
ZEND_METHOD(Redis, georadius);
ZEND_METHOD(Redis, georadius_ro);
ZEND_METHOD(Redis, georadiusbymember);
ZEND_METHOD(Redis, georadiusbymember_ro);
ZEND_METHOD(Redis, geosearch);
ZEND_METHOD(Redis, geosearchstore);
ZEND_METHOD(Redis, get);
ZEND_METHOD(Redis, getAuth);
ZEND_METHOD(Redis, getBit);
ZEND_METHOD(Redis, getEx);
ZEND_METHOD(Redis, getDBNum);
ZEND_METHOD(Redis, getDel);
ZEND_METHOD(Redis, getHost);
ZEND_METHOD(Redis, getLastError);
ZEND_METHOD(Redis, getMode);
ZEND_METHOD(Redis, getOption);
ZEND_METHOD(Redis, getPersistentID);
ZEND_METHOD(Redis, getPort);
ZEND_METHOD(Redis, getRange);
ZEND_METHOD(Redis, lcs);
ZEND_METHOD(Redis, getReadTimeout);
ZEND_METHOD(Redis, getset);
ZEND_METHOD(Redis, getTimeout);
ZEND_METHOD(Redis, getTransferredBytes);
ZEND_METHOD(Redis, clearTransferredBytes);
ZEND_METHOD(Redis, hDel);
ZEND_METHOD(Redis, hExists);
ZEND_METHOD(Redis, hGet);
ZEND_METHOD(Redis, hGetAll);
ZEND_METHOD(Redis, hIncrBy);
ZEND_METHOD(Redis, hIncrByFloat);
ZEND_METHOD(Redis, hKeys);
ZEND_METHOD(Redis, hLen);
ZEND_METHOD(Redis, hMget);
ZEND_METHOD(Redis, hMset);
ZEND_METHOD(Redis, hRandField);
ZEND_METHOD(Redis, hSet);
ZEND_METHOD(Redis, hSetNx);
ZEND_METHOD(Redis, hStrLen);
ZEND_METHOD(Redis, hVals);
ZEND_METHOD(Redis, hscan);
ZEND_METHOD(Redis, incr);
ZEND_METHOD(Redis, incrBy);
ZEND_METHOD(Redis, incrByFloat);
ZEND_METHOD(Redis, info);
ZEND_METHOD(Redis, isConnected);
ZEND_METHOD(Redis, keys);
ZEND_METHOD(Redis, lInsert);
ZEND_METHOD(Redis, lLen);
ZEND_METHOD(Redis, lMove);
ZEND_METHOD(Redis, blmove);
ZEND_METHOD(Redis, lPop);
ZEND_METHOD(Redis, lPos);
ZEND_METHOD(Redis, lPush);
ZEND_METHOD(Redis, rPush);
ZEND_METHOD(Redis, lPushx);
ZEND_METHOD(Redis, rPushx);
ZEND_METHOD(Redis, lSet);
ZEND_METHOD(Redis, lastSave);
ZEND_METHOD(Redis, lindex);
ZEND_METHOD(Redis, lrange);
ZEND_METHOD(Redis, lrem);
ZEND_METHOD(Redis, ltrim);
ZEND_METHOD(Redis, mget);
ZEND_METHOD(Redis, migrate);
ZEND_METHOD(Redis, move);
ZEND_METHOD(Redis, mset);
ZEND_METHOD(Redis, msetnx);
ZEND_METHOD(Redis, multi);
ZEND_METHOD(Redis, object);
ZEND_METHOD(Redis, pconnect);
ZEND_METHOD(Redis, persist);
ZEND_METHOD(Redis, pexpire);
ZEND_METHOD(Redis, pexpireAt);
ZEND_METHOD(Redis, pfadd);
ZEND_METHOD(Redis, pfcount);
ZEND_METHOD(Redis, pfmerge);
ZEND_METHOD(Redis, ping);
ZEND_METHOD(Redis, pipeline);
ZEND_METHOD(Redis, psetex);
ZEND_METHOD(Redis, psubscribe);
ZEND_METHOD(Redis, pttl);
ZEND_METHOD(Redis, publish);
ZEND_METHOD(Redis, pubsub);
ZEND_METHOD(Redis, punsubscribe);
ZEND_METHOD(Redis, rPop);
ZEND_METHOD(Redis, randomKey);
ZEND_METHOD(Redis, rawcommand);
ZEND_METHOD(Redis, rename);
ZEND_METHOD(Redis, renameNx);
ZEND_METHOD(Redis, reset);
ZEND_METHOD(Redis, restore);
ZEND_METHOD(Redis, role);
ZEND_METHOD(Redis, rpoplpush);
ZEND_METHOD(Redis, sAdd);
ZEND_METHOD(Redis, sAddArray);
ZEND_METHOD(Redis, sDiff);
ZEND_METHOD(Redis, sDiffStore);
ZEND_METHOD(Redis, sInter);
ZEND_METHOD(Redis, sintercard);
ZEND_METHOD(Redis, sInterStore);
ZEND_METHOD(Redis, sMembers);
ZEND_METHOD(Redis, sMisMember);
ZEND_METHOD(Redis, sMove);
ZEND_METHOD(Redis, sPop);
ZEND_METHOD(Redis, sRandMember);
ZEND_METHOD(Redis, sUnion);
ZEND_METHOD(Redis, sUnionStore);
ZEND_METHOD(Redis, save);
ZEND_METHOD(Redis, scan);
ZEND_METHOD(Redis, scard);
ZEND_METHOD(Redis, script);
ZEND_METHOD(Redis, select);
ZEND_METHOD(Redis, set);
ZEND_METHOD(Redis, setBit);
ZEND_METHOD(Redis, setRange);
ZEND_METHOD(Redis, setOption);
ZEND_METHOD(Redis, setex);
ZEND_METHOD(Redis, setnx);
ZEND_METHOD(Redis, sismember);
ZEND_METHOD(Redis, slaveof);
ZEND_METHOD(Redis, replicaof);
ZEND_METHOD(Redis, touch);
ZEND_METHOD(Redis, slowlog);
ZEND_METHOD(Redis, sort);
ZEND_METHOD(Redis, sort_ro);
ZEND_METHOD(Redis, sortAsc);
ZEND_METHOD(Redis, sortAscAlpha);
ZEND_METHOD(Redis, sortDesc);
ZEND_METHOD(Redis, sortDescAlpha);
ZEND_METHOD(Redis, srem);
ZEND_METHOD(Redis, sscan);
ZEND_METHOD(Redis, ssubscribe);
ZEND_METHOD(Redis, strlen);
ZEND_METHOD(Redis, subscribe);
ZEND_METHOD(Redis, sunsubscribe);
ZEND_METHOD(Redis, swapdb);
ZEND_METHOD(Redis, time);
ZEND_METHOD(Redis, ttl);
ZEND_METHOD(Redis, type);
ZEND_METHOD(Redis, unlink);
ZEND_METHOD(Redis, unsubscribe);
ZEND_METHOD(Redis, unwatch);
ZEND_METHOD(Redis, watch);
ZEND_METHOD(Redis, wait);
ZEND_METHOD(Redis, xack);
ZEND_METHOD(Redis, xadd);
ZEND_METHOD(Redis, xautoclaim);
ZEND_METHOD(Redis, xclaim);
ZEND_METHOD(Redis, xdel);
ZEND_METHOD(Redis, xgroup);
ZEND_METHOD(Redis, xinfo);
ZEND_METHOD(Redis, xlen);
ZEND_METHOD(Redis, xpending);
ZEND_METHOD(Redis, xrange);
ZEND_METHOD(Redis, xread);
ZEND_METHOD(Redis, xreadgroup);
ZEND_METHOD(Redis, xrevrange);
ZEND_METHOD(Redis, xtrim);
ZEND_METHOD(Redis, zAdd);
ZEND_METHOD(Redis, zCard);
ZEND_METHOD(Redis, zCount);
ZEND_METHOD(Redis, zIncrBy);
ZEND_METHOD(Redis, zLexCount);
ZEND_METHOD(Redis, zMscore);
ZEND_METHOD(Redis, zPopMax);
ZEND_METHOD(Redis, zPopMin);
ZEND_METHOD(Redis, zRange);
ZEND_METHOD(Redis, zRangeByLex);
ZEND_METHOD(Redis, zRangeByScore);
ZEND_METHOD(Redis, zrangestore);
ZEND_METHOD(Redis, zRandMember);
ZEND_METHOD(Redis, zRank);
ZEND_METHOD(Redis, zRem);
ZEND_METHOD(Redis, zRemRangeByLex);
ZEND_METHOD(Redis, zRemRangeByRank);
ZEND_METHOD(Redis, zRemRangeByScore);
ZEND_METHOD(Redis, zRevRange);
ZEND_METHOD(Redis, zRevRangeByLex);
ZEND_METHOD(Redis, zRevRangeByScore);
ZEND_METHOD(Redis, zRevRank);
ZEND_METHOD(Redis, zScore);
ZEND_METHOD(Redis, zdiff);
ZEND_METHOD(Redis, zdiffstore);
ZEND_METHOD(Redis, zinter);
ZEND_METHOD(Redis, zintercard);
ZEND_METHOD(Redis, zinterstore);
ZEND_METHOD(Redis, zscan);
ZEND_METHOD(Redis, zunion);
ZEND_METHOD(Redis, zunionstore);
static const zend_function_entry class_Redis_methods[] = {
ZEND_ME(Redis, __construct, arginfo_class_Redis___construct, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, __destruct, arginfo_class_Redis___destruct, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, _compress, arginfo_class_Redis__compress, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, _uncompress, arginfo_class_Redis__uncompress, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, _prefix, arginfo_class_Redis__prefix, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, _serialize, arginfo_class_Redis__serialize, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, _unserialize, arginfo_class_Redis__unserialize, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, _pack, arginfo_class_Redis__pack, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, _unpack, arginfo_class_Redis__unpack, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, acl, arginfo_class_Redis_acl, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, append, arginfo_class_Redis_append, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, auth, arginfo_class_Redis_auth, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, bgSave, arginfo_class_Redis_bgSave, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, bgrewriteaof, arginfo_class_Redis_bgrewriteaof, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, bitcount, arginfo_class_Redis_bitcount, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, bitop, arginfo_class_Redis_bitop, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, bitpos, arginfo_class_Redis_bitpos, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, blPop, arginfo_class_Redis_blPop, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, brPop, arginfo_class_Redis_brPop, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, brpoplpush, arginfo_class_Redis_brpoplpush, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, bzPopMax, arginfo_class_Redis_bzPopMax, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, bzPopMin, arginfo_class_Redis_bzPopMin, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, bzmpop, arginfo_class_Redis_bzmpop, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zmpop, arginfo_class_Redis_zmpop, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, blmpop, arginfo_class_Redis_blmpop, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lmpop, arginfo_class_Redis_lmpop, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, clearLastError, arginfo_class_Redis_clearLastError, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, client, arginfo_class_Redis_client, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, close, arginfo_class_Redis_close, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, command, arginfo_class_Redis_command, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, config, arginfo_class_Redis_config, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, connect, arginfo_class_Redis_connect, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, copy, arginfo_class_Redis_copy, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, dbSize, arginfo_class_Redis_dbSize, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, debug, arginfo_class_Redis_debug, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, decr, arginfo_class_Redis_decr, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, decrBy, arginfo_class_Redis_decrBy, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, del, arginfo_class_Redis_del, ZEND_ACC_PUBLIC)
ZEND_MALIAS(Redis, delete, del, arginfo_class_Redis_delete, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
ZEND_ME(Redis, discard, arginfo_class_Redis_discard, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, dump, arginfo_class_Redis_dump, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, echo, arginfo_class_Redis_echo, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, eval, arginfo_class_Redis_eval, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, eval_ro, arginfo_class_Redis_eval_ro, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, evalsha, arginfo_class_Redis_evalsha, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, evalsha_ro, arginfo_class_Redis_evalsha_ro, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, exec, arginfo_class_Redis_exec, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, exists, arginfo_class_Redis_exists, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, expire, arginfo_class_Redis_expire, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, expireAt, arginfo_class_Redis_expireAt, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, failover, arginfo_class_Redis_failover, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, expiretime, arginfo_class_Redis_expiretime, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, pexpiretime, arginfo_class_Redis_pexpiretime, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, fcall, arginfo_class_Redis_fcall, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, fcall_ro, arginfo_class_Redis_fcall_ro, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, flushAll, arginfo_class_Redis_flushAll, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, flushDB, arginfo_class_Redis_flushDB, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, function, arginfo_class_Redis_function, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, geoadd, arginfo_class_Redis_geoadd, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, geodist, arginfo_class_Redis_geodist, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, geohash, arginfo_class_Redis_geohash, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, geopos, arginfo_class_Redis_geopos, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, georadius, arginfo_class_Redis_georadius, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, georadius_ro, arginfo_class_Redis_georadius_ro, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, georadiusbymember, arginfo_class_Redis_georadiusbymember, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, georadiusbymember_ro, arginfo_class_Redis_georadiusbymember_ro, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, geosearch, arginfo_class_Redis_geosearch, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, geosearchstore, arginfo_class_Redis_geosearchstore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, get, arginfo_class_Redis_get, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getAuth, arginfo_class_Redis_getAuth, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getBit, arginfo_class_Redis_getBit, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getEx, arginfo_class_Redis_getEx, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getDBNum, arginfo_class_Redis_getDBNum, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getDel, arginfo_class_Redis_getDel, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getHost, arginfo_class_Redis_getHost, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getLastError, arginfo_class_Redis_getLastError, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getMode, arginfo_class_Redis_getMode, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getOption, arginfo_class_Redis_getOption, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getPersistentID, arginfo_class_Redis_getPersistentID, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getPort, arginfo_class_Redis_getPort, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getRange, arginfo_class_Redis_getRange, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lcs, arginfo_class_Redis_lcs, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getReadTimeout, arginfo_class_Redis_getReadTimeout, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getset, arginfo_class_Redis_getset, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getTimeout, arginfo_class_Redis_getTimeout, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getTransferredBytes, arginfo_class_Redis_getTransferredBytes, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, clearTransferredBytes, arginfo_class_Redis_clearTransferredBytes, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hDel, arginfo_class_Redis_hDel, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hExists, arginfo_class_Redis_hExists, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hGet, arginfo_class_Redis_hGet, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hGetAll, arginfo_class_Redis_hGetAll, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hIncrBy, arginfo_class_Redis_hIncrBy, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hIncrByFloat, arginfo_class_Redis_hIncrByFloat, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hKeys, arginfo_class_Redis_hKeys, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hLen, arginfo_class_Redis_hLen, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hMget, arginfo_class_Redis_hMget, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hMset, arginfo_class_Redis_hMset, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hRandField, arginfo_class_Redis_hRandField, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hSet, arginfo_class_Redis_hSet, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hSetNx, arginfo_class_Redis_hSetNx, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hStrLen, arginfo_class_Redis_hStrLen, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hVals, arginfo_class_Redis_hVals, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, hscan, arginfo_class_Redis_hscan, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, incr, arginfo_class_Redis_incr, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, incrBy, arginfo_class_Redis_incrBy, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, incrByFloat, arginfo_class_Redis_incrByFloat, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, info, arginfo_class_Redis_info, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, isConnected, arginfo_class_Redis_isConnected, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, keys, arginfo_class_Redis_keys, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lInsert, arginfo_class_Redis_lInsert, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lLen, arginfo_class_Redis_lLen, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lMove, arginfo_class_Redis_lMove, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, blmove, arginfo_class_Redis_blmove, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lPop, arginfo_class_Redis_lPop, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lPos, arginfo_class_Redis_lPos, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lPush, arginfo_class_Redis_lPush, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, rPush, arginfo_class_Redis_rPush, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lPushx, arginfo_class_Redis_lPushx, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, rPushx, arginfo_class_Redis_rPushx, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lSet, arginfo_class_Redis_lSet, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lastSave, arginfo_class_Redis_lastSave, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lindex, arginfo_class_Redis_lindex, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lrange, arginfo_class_Redis_lrange, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, lrem, arginfo_class_Redis_lrem, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, ltrim, arginfo_class_Redis_ltrim, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, mget, arginfo_class_Redis_mget, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, migrate, arginfo_class_Redis_migrate, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, move, arginfo_class_Redis_move, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, mset, arginfo_class_Redis_mset, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, msetnx, arginfo_class_Redis_msetnx, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, multi, arginfo_class_Redis_multi, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, object, arginfo_class_Redis_object, ZEND_ACC_PUBLIC)
ZEND_MALIAS(Redis, open, connect, arginfo_class_Redis_open, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
ZEND_ME(Redis, pconnect, arginfo_class_Redis_pconnect, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, persist, arginfo_class_Redis_persist, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, pexpire, arginfo_class_Redis_pexpire, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, pexpireAt, arginfo_class_Redis_pexpireAt, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, pfadd, arginfo_class_Redis_pfadd, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, pfcount, arginfo_class_Redis_pfcount, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, pfmerge, arginfo_class_Redis_pfmerge, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, ping, arginfo_class_Redis_ping, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, pipeline, arginfo_class_Redis_pipeline, ZEND_ACC_PUBLIC)
ZEND_MALIAS(Redis, popen, pconnect, arginfo_class_Redis_popen, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
ZEND_ME(Redis, psetex, arginfo_class_Redis_psetex, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, psubscribe, arginfo_class_Redis_psubscribe, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, pttl, arginfo_class_Redis_pttl, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, publish, arginfo_class_Redis_publish, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, pubsub, arginfo_class_Redis_pubsub, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, punsubscribe, arginfo_class_Redis_punsubscribe, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, rPop, arginfo_class_Redis_rPop, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, randomKey, arginfo_class_Redis_randomKey, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, rawcommand, arginfo_class_Redis_rawcommand, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, rename, arginfo_class_Redis_rename, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, renameNx, arginfo_class_Redis_renameNx, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, reset, arginfo_class_Redis_reset, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, restore, arginfo_class_Redis_restore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, role, arginfo_class_Redis_role, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, rpoplpush, arginfo_class_Redis_rpoplpush, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sAdd, arginfo_class_Redis_sAdd, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sAddArray, arginfo_class_Redis_sAddArray, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sDiff, arginfo_class_Redis_sDiff, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sDiffStore, arginfo_class_Redis_sDiffStore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sInter, arginfo_class_Redis_sInter, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sintercard, arginfo_class_Redis_sintercard, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sInterStore, arginfo_class_Redis_sInterStore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sMembers, arginfo_class_Redis_sMembers, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sMisMember, arginfo_class_Redis_sMisMember, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sMove, arginfo_class_Redis_sMove, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sPop, arginfo_class_Redis_sPop, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sRandMember, arginfo_class_Redis_sRandMember, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sUnion, arginfo_class_Redis_sUnion, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sUnionStore, arginfo_class_Redis_sUnionStore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, save, arginfo_class_Redis_save, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, scan, arginfo_class_Redis_scan, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, scard, arginfo_class_Redis_scard, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, script, arginfo_class_Redis_script, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, select, arginfo_class_Redis_select, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, set, arginfo_class_Redis_set, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, setBit, arginfo_class_Redis_setBit, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, setRange, arginfo_class_Redis_setRange, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, setOption, arginfo_class_Redis_setOption, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, setex, arginfo_class_Redis_setex, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, setnx, arginfo_class_Redis_setnx, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sismember, arginfo_class_Redis_sismember, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, slaveof, arginfo_class_Redis_slaveof, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
ZEND_ME(Redis, replicaof, arginfo_class_Redis_replicaof, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, touch, arginfo_class_Redis_touch, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, slowlog, arginfo_class_Redis_slowlog, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sort, arginfo_class_Redis_sort, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sort_ro, arginfo_class_Redis_sort_ro, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sortAsc, arginfo_class_Redis_sortAsc, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
ZEND_ME(Redis, sortAscAlpha, arginfo_class_Redis_sortAscAlpha, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
ZEND_ME(Redis, sortDesc, arginfo_class_Redis_sortDesc, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
ZEND_ME(Redis, sortDescAlpha, arginfo_class_Redis_sortDescAlpha, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
ZEND_ME(Redis, srem, arginfo_class_Redis_srem, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sscan, arginfo_class_Redis_sscan, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, ssubscribe, arginfo_class_Redis_ssubscribe, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, strlen, arginfo_class_Redis_strlen, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, subscribe, arginfo_class_Redis_subscribe, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, sunsubscribe, arginfo_class_Redis_sunsubscribe, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, swapdb, arginfo_class_Redis_swapdb, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, time, arginfo_class_Redis_time, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, ttl, arginfo_class_Redis_ttl, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, type, arginfo_class_Redis_type, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, unlink, arginfo_class_Redis_unlink, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, unsubscribe, arginfo_class_Redis_unsubscribe, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, unwatch, arginfo_class_Redis_unwatch, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, watch, arginfo_class_Redis_watch, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, wait, arginfo_class_Redis_wait, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xack, arginfo_class_Redis_xack, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xadd, arginfo_class_Redis_xadd, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xautoclaim, arginfo_class_Redis_xautoclaim, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xclaim, arginfo_class_Redis_xclaim, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xdel, arginfo_class_Redis_xdel, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xgroup, arginfo_class_Redis_xgroup, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xinfo, arginfo_class_Redis_xinfo, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xlen, arginfo_class_Redis_xlen, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xpending, arginfo_class_Redis_xpending, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xrange, arginfo_class_Redis_xrange, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xread, arginfo_class_Redis_xread, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xreadgroup, arginfo_class_Redis_xreadgroup, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xrevrange, arginfo_class_Redis_xrevrange, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, xtrim, arginfo_class_Redis_xtrim, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zAdd, arginfo_class_Redis_zAdd, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zCard, arginfo_class_Redis_zCard, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zCount, arginfo_class_Redis_zCount, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zIncrBy, arginfo_class_Redis_zIncrBy, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zLexCount, arginfo_class_Redis_zLexCount, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zMscore, arginfo_class_Redis_zMscore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zPopMax, arginfo_class_Redis_zPopMax, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zPopMin, arginfo_class_Redis_zPopMin, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRange, arginfo_class_Redis_zRange, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRangeByLex, arginfo_class_Redis_zRangeByLex, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRangeByScore, arginfo_class_Redis_zRangeByScore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zrangestore, arginfo_class_Redis_zrangestore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRandMember, arginfo_class_Redis_zRandMember, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRank, arginfo_class_Redis_zRank, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRem, arginfo_class_Redis_zRem, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRemRangeByLex, arginfo_class_Redis_zRemRangeByLex, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRemRangeByRank, arginfo_class_Redis_zRemRangeByRank, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRemRangeByScore, arginfo_class_Redis_zRemRangeByScore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRevRange, arginfo_class_Redis_zRevRange, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRevRangeByLex, arginfo_class_Redis_zRevRangeByLex, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRevRangeByScore, arginfo_class_Redis_zRevRangeByScore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRevRank, arginfo_class_Redis_zRevRank, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zScore, arginfo_class_Redis_zScore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zdiff, arginfo_class_Redis_zdiff, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zdiffstore, arginfo_class_Redis_zdiffstore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zinter, arginfo_class_Redis_zinter, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zintercard, arginfo_class_Redis_zintercard, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zinterstore, arginfo_class_Redis_zinterstore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zscan, arginfo_class_Redis_zscan, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zunion, arginfo_class_Redis_zunion, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zunionstore, arginfo_class_Redis_zunionstore, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
static const zend_function_entry class_RedisException_methods[] = {
ZEND_FE_END
};
static zend_class_entry *register_class_Redis(void)
{
zend_class_entry ce, *class_entry;
INIT_CLASS_ENTRY(ce, "Redis", class_Redis_methods);
class_entry = zend_register_internal_class_ex(&ce, NULL);
zval const_REDIS_NOT_FOUND_value;
ZVAL_LONG(&const_REDIS_NOT_FOUND_value, REDIS_NOT_FOUND);
zend_string *const_REDIS_NOT_FOUND_name = zend_string_init_interned("REDIS_NOT_FOUND", sizeof("REDIS_NOT_FOUND") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_REDIS_NOT_FOUND_name, &const_REDIS_NOT_FOUND_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_REDIS_NOT_FOUND_name);
zval const_REDIS_STRING_value;
ZVAL_LONG(&const_REDIS_STRING_value, REDIS_STRING);
zend_string *const_REDIS_STRING_name = zend_string_init_interned("REDIS_STRING", sizeof("REDIS_STRING") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_REDIS_STRING_name, &const_REDIS_STRING_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_REDIS_STRING_name);
zval const_REDIS_SET_value;
ZVAL_LONG(&const_REDIS_SET_value, REDIS_SET);
zend_string *const_REDIS_SET_name = zend_string_init_interned("REDIS_SET", sizeof("REDIS_SET") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_REDIS_SET_name, &const_REDIS_SET_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_REDIS_SET_name);
zval const_REDIS_LIST_value;
ZVAL_LONG(&const_REDIS_LIST_value, REDIS_LIST);
zend_string *const_REDIS_LIST_name = zend_string_init_interned("REDIS_LIST", sizeof("REDIS_LIST") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_REDIS_LIST_name, &const_REDIS_LIST_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_REDIS_LIST_name);
zval const_REDIS_ZSET_value;
ZVAL_LONG(&const_REDIS_ZSET_value, REDIS_ZSET);
zend_string *const_REDIS_ZSET_name = zend_string_init_interned("REDIS_ZSET", sizeof("REDIS_ZSET") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_REDIS_ZSET_name, &const_REDIS_ZSET_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_REDIS_ZSET_name);
zval const_REDIS_HASH_value;
ZVAL_LONG(&const_REDIS_HASH_value, REDIS_HASH);
zend_string *const_REDIS_HASH_name = zend_string_init_interned("REDIS_HASH", sizeof("REDIS_HASH") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_REDIS_HASH_name, &const_REDIS_HASH_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_REDIS_HASH_name);
zval const_REDIS_STREAM_value;
ZVAL_LONG(&const_REDIS_STREAM_value, REDIS_STREAM);
zend_string *const_REDIS_STREAM_name = zend_string_init_interned("REDIS_STREAM", sizeof("REDIS_STREAM") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_REDIS_STREAM_name, &const_REDIS_STREAM_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_REDIS_STREAM_name);
zval const_ATOMIC_value;
ZVAL_LONG(&const_ATOMIC_value, ATOMIC);
zend_string *const_ATOMIC_name = zend_string_init_interned("ATOMIC", sizeof("ATOMIC") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_ATOMIC_name, &const_ATOMIC_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_ATOMIC_name);
zval const_MULTI_value;
ZVAL_LONG(&const_MULTI_value, MULTI);
zend_string *const_MULTI_name = zend_string_init_interned("MULTI", sizeof("MULTI") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_MULTI_name, &const_MULTI_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_MULTI_name);
zval const_PIPELINE_value;
ZVAL_LONG(&const_PIPELINE_value, PIPELINE);
zend_string *const_PIPELINE_name = zend_string_init_interned("PIPELINE", sizeof("PIPELINE") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_PIPELINE_name, &const_PIPELINE_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_PIPELINE_name);
zval const_OPT_SERIALIZER_value;
ZVAL_LONG(&const_OPT_SERIALIZER_value, REDIS_OPT_SERIALIZER);
zend_string *const_OPT_SERIALIZER_name = zend_string_init_interned("OPT_SERIALIZER", sizeof("OPT_SERIALIZER") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_SERIALIZER_name, &const_OPT_SERIALIZER_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_SERIALIZER_name);
zval const_OPT_PREFIX_value;
ZVAL_LONG(&const_OPT_PREFIX_value, REDIS_OPT_PREFIX);
zend_string *const_OPT_PREFIX_name = zend_string_init_interned("OPT_PREFIX", sizeof("OPT_PREFIX") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_PREFIX_name, &const_OPT_PREFIX_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_PREFIX_name);
zval const_OPT_READ_TIMEOUT_value;
ZVAL_LONG(&const_OPT_READ_TIMEOUT_value, REDIS_OPT_READ_TIMEOUT);
zend_string *const_OPT_READ_TIMEOUT_name = zend_string_init_interned("OPT_READ_TIMEOUT", sizeof("OPT_READ_TIMEOUT") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_READ_TIMEOUT_name, &const_OPT_READ_TIMEOUT_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_READ_TIMEOUT_name);
zval const_OPT_TCP_KEEPALIVE_value;
ZVAL_LONG(&const_OPT_TCP_KEEPALIVE_value, REDIS_OPT_TCP_KEEPALIVE);
zend_string *const_OPT_TCP_KEEPALIVE_name = zend_string_init_interned("OPT_TCP_KEEPALIVE", sizeof("OPT_TCP_KEEPALIVE") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_TCP_KEEPALIVE_name, &const_OPT_TCP_KEEPALIVE_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_TCP_KEEPALIVE_name);
zval const_OPT_COMPRESSION_value;
ZVAL_LONG(&const_OPT_COMPRESSION_value, REDIS_OPT_COMPRESSION);
zend_string *const_OPT_COMPRESSION_name = zend_string_init_interned("OPT_COMPRESSION", sizeof("OPT_COMPRESSION") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_COMPRESSION_name, &const_OPT_COMPRESSION_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_COMPRESSION_name);
zval const_OPT_REPLY_LITERAL_value;
ZVAL_LONG(&const_OPT_REPLY_LITERAL_value, REDIS_OPT_REPLY_LITERAL);
zend_string *const_OPT_REPLY_LITERAL_name = zend_string_init_interned("OPT_REPLY_LITERAL", sizeof("OPT_REPLY_LITERAL") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_REPLY_LITERAL_name, &const_OPT_REPLY_LITERAL_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_REPLY_LITERAL_name);
zval const_OPT_COMPRESSION_LEVEL_value;
ZVAL_LONG(&const_OPT_COMPRESSION_LEVEL_value, REDIS_OPT_COMPRESSION_LEVEL);
zend_string *const_OPT_COMPRESSION_LEVEL_name = zend_string_init_interned("OPT_COMPRESSION_LEVEL", sizeof("OPT_COMPRESSION_LEVEL") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_COMPRESSION_LEVEL_name, &const_OPT_COMPRESSION_LEVEL_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_COMPRESSION_LEVEL_name);
zval const_OPT_NULL_MULTIBULK_AS_NULL_value;
ZVAL_LONG(&const_OPT_NULL_MULTIBULK_AS_NULL_value, REDIS_OPT_NULL_MBULK_AS_NULL);
zend_string *const_OPT_NULL_MULTIBULK_AS_NULL_name = zend_string_init_interned("OPT_NULL_MULTIBULK_AS_NULL", sizeof("OPT_NULL_MULTIBULK_AS_NULL") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_NULL_MULTIBULK_AS_NULL_name, &const_OPT_NULL_MULTIBULK_AS_NULL_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_NULL_MULTIBULK_AS_NULL_name);
zval const_SERIALIZER_NONE_value;
ZVAL_LONG(&const_SERIALIZER_NONE_value, REDIS_SERIALIZER_NONE);
zend_string *const_SERIALIZER_NONE_name = zend_string_init_interned("SERIALIZER_NONE", sizeof("SERIALIZER_NONE") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_SERIALIZER_NONE_name, &const_SERIALIZER_NONE_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_SERIALIZER_NONE_name);
zval const_SERIALIZER_PHP_value;
ZVAL_LONG(&const_SERIALIZER_PHP_value, REDIS_SERIALIZER_PHP);
zend_string *const_SERIALIZER_PHP_name = zend_string_init_interned("SERIALIZER_PHP", sizeof("SERIALIZER_PHP") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_SERIALIZER_PHP_name, &const_SERIALIZER_PHP_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_SERIALIZER_PHP_name);
#if defined(HAVE_REDIS_IGBINARY)
zval const_SERIALIZER_IGBINARY_value;
ZVAL_LONG(&const_SERIALIZER_IGBINARY_value, REDIS_SERIALIZER_IGBINARY);
zend_string *const_SERIALIZER_IGBINARY_name = zend_string_init_interned("SERIALIZER_IGBINARY", sizeof("SERIALIZER_IGBINARY") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_SERIALIZER_IGBINARY_name, &const_SERIALIZER_IGBINARY_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_SERIALIZER_IGBINARY_name);
#endif
#if defined(HAVE_REDIS_MSGPACK)
zval const_SERIALIZER_MSGPACK_value;
ZVAL_LONG(&const_SERIALIZER_MSGPACK_value, REDIS_SERIALIZER_MSGPACK);
zend_string *const_SERIALIZER_MSGPACK_name = zend_string_init_interned("SERIALIZER_MSGPACK", sizeof("SERIALIZER_MSGPACK") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_SERIALIZER_MSGPACK_name, &const_SERIALIZER_MSGPACK_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_SERIALIZER_MSGPACK_name);
#endif
zval const_SERIALIZER_JSON_value;
ZVAL_LONG(&const_SERIALIZER_JSON_value, REDIS_SERIALIZER_JSON);
zend_string *const_SERIALIZER_JSON_name = zend_string_init_interned("SERIALIZER_JSON", sizeof("SERIALIZER_JSON") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_SERIALIZER_JSON_name, &const_SERIALIZER_JSON_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_SERIALIZER_JSON_name);
zval const_COMPRESSION_NONE_value;
ZVAL_LONG(&const_COMPRESSION_NONE_value, REDIS_COMPRESSION_NONE);
zend_string *const_COMPRESSION_NONE_name = zend_string_init_interned("COMPRESSION_NONE", sizeof("COMPRESSION_NONE") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_COMPRESSION_NONE_name, &const_COMPRESSION_NONE_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_COMPRESSION_NONE_name);
#if defined(HAVE_REDIS_LZF)
zval const_COMPRESSION_LZF_value;
ZVAL_LONG(&const_COMPRESSION_LZF_value, REDIS_COMPRESSION_LZF);
zend_string *const_COMPRESSION_LZF_name = zend_string_init_interned("COMPRESSION_LZF", sizeof("COMPRESSION_LZF") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_COMPRESSION_LZF_name, &const_COMPRESSION_LZF_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_COMPRESSION_LZF_name);
#endif
#if defined(HAVE_REDIS_ZSTD)
zval const_COMPRESSION_ZSTD_value;
ZVAL_LONG(&const_COMPRESSION_ZSTD_value, REDIS_COMPRESSION_ZSTD);
zend_string *const_COMPRESSION_ZSTD_name = zend_string_init_interned("COMPRESSION_ZSTD", sizeof("COMPRESSION_ZSTD") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_COMPRESSION_ZSTD_name, &const_COMPRESSION_ZSTD_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_COMPRESSION_ZSTD_name);
#endif
#if defined(HAVE_REDIS_ZSTD) && defined(ZSTD_CLEVEL_DEFAULT)
zval const_COMPRESSION_ZSTD_DEFAULT_value;
ZVAL_LONG(&const_COMPRESSION_ZSTD_DEFAULT_value, ZSTD_CLEVEL_DEFAULT);
zend_string *const_COMPRESSION_ZSTD_DEFAULT_name = zend_string_init_interned("COMPRESSION_ZSTD_DEFAULT", sizeof("COMPRESSION_ZSTD_DEFAULT") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_COMPRESSION_ZSTD_DEFAULT_name, &const_COMPRESSION_ZSTD_DEFAULT_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_COMPRESSION_ZSTD_DEFAULT_name);
#endif
#if defined(HAVE_REDIS_ZSTD) && !(defined(ZSTD_CLEVEL_DEFAULT))
zval const_COMPRESSION_ZSTD_DEFAULT_value;
ZVAL_LONG(&const_COMPRESSION_ZSTD_DEFAULT_value, 3);
zend_string *const_COMPRESSION_ZSTD_DEFAULT_name = zend_string_init_interned("COMPRESSION_ZSTD_DEFAULT", sizeof("COMPRESSION_ZSTD_DEFAULT") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_COMPRESSION_ZSTD_DEFAULT_name, &const_COMPRESSION_ZSTD_DEFAULT_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_COMPRESSION_ZSTD_DEFAULT_name);
#endif
#if defined(HAVE_REDIS_ZSTD) && defined(ZSTD_CLEVEL_MAX)
zval const_COMPRESSION_ZSTD_MAX_value;
ZVAL_LONG(&const_COMPRESSION_ZSTD_MAX_value, ZSTD_CLEVEL_MAX);
zend_string *const_COMPRESSION_ZSTD_MAX_name = zend_string_init_interned("COMPRESSION_ZSTD_MAX", sizeof("COMPRESSION_ZSTD_MAX") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_COMPRESSION_ZSTD_MAX_name, &const_COMPRESSION_ZSTD_MAX_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_COMPRESSION_ZSTD_MAX_name);
#endif
#if defined(HAVE_REDIS_ZSTD)
zval const_COMPRESSION_ZSTD_MAX_value;
ZVAL_LONG(&const_COMPRESSION_ZSTD_MAX_value, ZSTD_maxCLevel());
zend_string *const_COMPRESSION_ZSTD_MAX_name = zend_string_init_interned("COMPRESSION_ZSTD_MAX", sizeof("COMPRESSION_ZSTD_MAX") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_COMPRESSION_ZSTD_MAX_name, &const_COMPRESSION_ZSTD_MAX_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_COMPRESSION_ZSTD_MAX_name);
#endif
#if defined(HAVE_REDIS_LZ4)
zval const_COMPRESSION_LZ4_value;
ZVAL_LONG(&const_COMPRESSION_LZ4_value, REDIS_COMPRESSION_LZ4);
zend_string *const_COMPRESSION_LZ4_name = zend_string_init_interned("COMPRESSION_LZ4", sizeof("COMPRESSION_LZ4") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_COMPRESSION_LZ4_name, &const_COMPRESSION_LZ4_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_COMPRESSION_LZ4_name);
#endif
zval const_OPT_SCAN_value;
ZVAL_LONG(&const_OPT_SCAN_value, REDIS_OPT_SCAN);
zend_string *const_OPT_SCAN_name = zend_string_init_interned("OPT_SCAN", sizeof("OPT_SCAN") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_SCAN_name, &const_OPT_SCAN_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_SCAN_name);
zval const_SCAN_RETRY_value;
ZVAL_LONG(&const_SCAN_RETRY_value, REDIS_SCAN_RETRY);
zend_string *const_SCAN_RETRY_name = zend_string_init_interned("SCAN_RETRY", sizeof("SCAN_RETRY") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_SCAN_RETRY_name, &const_SCAN_RETRY_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_SCAN_RETRY_name);
zval const_SCAN_NORETRY_value;
ZVAL_LONG(&const_SCAN_NORETRY_value, REDIS_SCAN_NORETRY);
zend_string *const_SCAN_NORETRY_name = zend_string_init_interned("SCAN_NORETRY", sizeof("SCAN_NORETRY") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_SCAN_NORETRY_name, &const_SCAN_NORETRY_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_SCAN_NORETRY_name);
zval const_SCAN_PREFIX_value;
ZVAL_LONG(&const_SCAN_PREFIX_value, REDIS_SCAN_PREFIX);
zend_string *const_SCAN_PREFIX_name = zend_string_init_interned("SCAN_PREFIX", sizeof("SCAN_PREFIX") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_SCAN_PREFIX_name, &const_SCAN_PREFIX_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_SCAN_PREFIX_name);
zval const_SCAN_NOPREFIX_value;
ZVAL_LONG(&const_SCAN_NOPREFIX_value, REDIS_SCAN_NOPREFIX);
zend_string *const_SCAN_NOPREFIX_name = zend_string_init_interned("SCAN_NOPREFIX", sizeof("SCAN_NOPREFIX") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_SCAN_NOPREFIX_name, &const_SCAN_NOPREFIX_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_SCAN_NOPREFIX_name);
zval const_BEFORE_value;
zend_string *const_BEFORE_value_str = zend_string_init("before", strlen("before"), 1);
ZVAL_STR(&const_BEFORE_value, const_BEFORE_value_str);
zend_string *const_BEFORE_name = zend_string_init_interned("BEFORE", sizeof("BEFORE") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_BEFORE_name, &const_BEFORE_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_BEFORE_name);
zval const_AFTER_value;
zend_string *const_AFTER_value_str = zend_string_init("after", strlen("after"), 1);
ZVAL_STR(&const_AFTER_value, const_AFTER_value_str);
zend_string *const_AFTER_name = zend_string_init_interned("AFTER", sizeof("AFTER") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_AFTER_name, &const_AFTER_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_AFTER_name);
zval const_LEFT_value;
zend_string *const_LEFT_value_str = zend_string_init("left", strlen("left"), 1);
ZVAL_STR(&const_LEFT_value, const_LEFT_value_str);
zend_string *const_LEFT_name = zend_string_init_interned("LEFT", sizeof("LEFT") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_LEFT_name, &const_LEFT_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_LEFT_name);
zval const_RIGHT_value;
zend_string *const_RIGHT_value_str = zend_string_init("right", strlen("right"), 1);
ZVAL_STR(&const_RIGHT_value, const_RIGHT_value_str);
zend_string *const_RIGHT_name = zend_string_init_interned("RIGHT", sizeof("RIGHT") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_RIGHT_name, &const_RIGHT_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_RIGHT_name);
zval const_OPT_MAX_RETRIES_value;
ZVAL_LONG(&const_OPT_MAX_RETRIES_value, REDIS_OPT_MAX_RETRIES);
zend_string *const_OPT_MAX_RETRIES_name = zend_string_init_interned("OPT_MAX_RETRIES", sizeof("OPT_MAX_RETRIES") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_MAX_RETRIES_name, &const_OPT_MAX_RETRIES_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_MAX_RETRIES_name);
zval const_OPT_BACKOFF_ALGORITHM_value;
ZVAL_LONG(&const_OPT_BACKOFF_ALGORITHM_value, REDIS_OPT_BACKOFF_ALGORITHM);
zend_string *const_OPT_BACKOFF_ALGORITHM_name = zend_string_init_interned("OPT_BACKOFF_ALGORITHM", sizeof("OPT_BACKOFF_ALGORITHM") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_BACKOFF_ALGORITHM_name, &const_OPT_BACKOFF_ALGORITHM_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_BACKOFF_ALGORITHM_name);
zval const_BACKOFF_ALGORITHM_DEFAULT_value;
ZVAL_LONG(&const_BACKOFF_ALGORITHM_DEFAULT_value, REDIS_BACKOFF_ALGORITHM_DEFAULT);
zend_string *const_BACKOFF_ALGORITHM_DEFAULT_name = zend_string_init_interned("BACKOFF_ALGORITHM_DEFAULT", sizeof("BACKOFF_ALGORITHM_DEFAULT") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_BACKOFF_ALGORITHM_DEFAULT_name, &const_BACKOFF_ALGORITHM_DEFAULT_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_BACKOFF_ALGORITHM_DEFAULT_name);
zval const_BACKOFF_ALGORITHM_CONSTANT_value;
ZVAL_LONG(&const_BACKOFF_ALGORITHM_CONSTANT_value, REDIS_BACKOFF_ALGORITHM_CONSTANT);
zend_string *const_BACKOFF_ALGORITHM_CONSTANT_name = zend_string_init_interned("BACKOFF_ALGORITHM_CONSTANT", sizeof("BACKOFF_ALGORITHM_CONSTANT") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_BACKOFF_ALGORITHM_CONSTANT_name, &const_BACKOFF_ALGORITHM_CONSTANT_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_BACKOFF_ALGORITHM_CONSTANT_name);
zval const_BACKOFF_ALGORITHM_UNIFORM_value;
ZVAL_LONG(&const_BACKOFF_ALGORITHM_UNIFORM_value, REDIS_BACKOFF_ALGORITHM_UNIFORM);
zend_string *const_BACKOFF_ALGORITHM_UNIFORM_name = zend_string_init_interned("BACKOFF_ALGORITHM_UNIFORM", sizeof("BACKOFF_ALGORITHM_UNIFORM") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_BACKOFF_ALGORITHM_UNIFORM_name, &const_BACKOFF_ALGORITHM_UNIFORM_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_BACKOFF_ALGORITHM_UNIFORM_name);
zval const_BACKOFF_ALGORITHM_EXPONENTIAL_value;
ZVAL_LONG(&const_BACKOFF_ALGORITHM_EXPONENTIAL_value, REDIS_BACKOFF_ALGORITHM_EXPONENTIAL);
zend_string *const_BACKOFF_ALGORITHM_EXPONENTIAL_name = zend_string_init_interned("BACKOFF_ALGORITHM_EXPONENTIAL", sizeof("BACKOFF_ALGORITHM_EXPONENTIAL") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_BACKOFF_ALGORITHM_EXPONENTIAL_name, &const_BACKOFF_ALGORITHM_EXPONENTIAL_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_BACKOFF_ALGORITHM_EXPONENTIAL_name);
zval const_BACKOFF_ALGORITHM_FULL_JITTER_value;
ZVAL_LONG(&const_BACKOFF_ALGORITHM_FULL_JITTER_value, REDIS_BACKOFF_ALGORITHM_FULL_JITTER);
zend_string *const_BACKOFF_ALGORITHM_FULL_JITTER_name = zend_string_init_interned("BACKOFF_ALGORITHM_FULL_JITTER", sizeof("BACKOFF_ALGORITHM_FULL_JITTER") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_BACKOFF_ALGORITHM_FULL_JITTER_name, &const_BACKOFF_ALGORITHM_FULL_JITTER_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_BACKOFF_ALGORITHM_FULL_JITTER_name);
zval const_BACKOFF_ALGORITHM_EQUAL_JITTER_value;
ZVAL_LONG(&const_BACKOFF_ALGORITHM_EQUAL_JITTER_value, REDIS_BACKOFF_ALGORITHM_EQUAL_JITTER);
zend_string *const_BACKOFF_ALGORITHM_EQUAL_JITTER_name = zend_string_init_interned("BACKOFF_ALGORITHM_EQUAL_JITTER", sizeof("BACKOFF_ALGORITHM_EQUAL_JITTER") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_BACKOFF_ALGORITHM_EQUAL_JITTER_name, &const_BACKOFF_ALGORITHM_EQUAL_JITTER_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_BACKOFF_ALGORITHM_EQUAL_JITTER_name);
zval const_BACKOFF_ALGORITHM_DECORRELATED_JITTER_value;
ZVAL_LONG(&const_BACKOFF_ALGORITHM_DECORRELATED_JITTER_value, REDIS_BACKOFF_ALGORITHM_DECORRELATED_JITTER);
zend_string *const_BACKOFF_ALGORITHM_DECORRELATED_JITTER_name = zend_string_init_interned("BACKOFF_ALGORITHM_DECORRELATED_JITTER", sizeof("BACKOFF_ALGORITHM_DECORRELATED_JITTER") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_BACKOFF_ALGORITHM_DECORRELATED_JITTER_name, &const_BACKOFF_ALGORITHM_DECORRELATED_JITTER_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_BACKOFF_ALGORITHM_DECORRELATED_JITTER_name);
zval const_OPT_BACKOFF_BASE_value;
ZVAL_LONG(&const_OPT_BACKOFF_BASE_value, REDIS_OPT_BACKOFF_BASE);
zend_string *const_OPT_BACKOFF_BASE_name = zend_string_init_interned("OPT_BACKOFF_BASE", sizeof("OPT_BACKOFF_BASE") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_BACKOFF_BASE_name, &const_OPT_BACKOFF_BASE_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_BACKOFF_BASE_name);
zval const_OPT_BACKOFF_CAP_value;
ZVAL_LONG(&const_OPT_BACKOFF_CAP_value, REDIS_OPT_BACKOFF_CAP);
zend_string *const_OPT_BACKOFF_CAP_name = zend_string_init_interned("OPT_BACKOFF_CAP", sizeof("OPT_BACKOFF_CAP") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_BACKOFF_CAP_name, &const_OPT_BACKOFF_CAP_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_BACKOFF_CAP_name);
return class_entry;
}
static zend_class_entry *register_class_RedisException(zend_class_entry *class_entry_RuntimeException)
{
zend_class_entry ce, *class_entry;
INIT_CLASS_ENTRY(ce, "RedisException", class_RedisException_methods);
class_entry = zend_register_internal_class_ex(&ce, class_entry_RuntimeException);
return class_entry;
}
redis-6.0.2/redis_array.c 0000644 0001750 0000012 00000107476 14515245367 016107 0 ustar pyatsukhnenko wheel /*
+----------------------------------------------------------------------+
| Copyright (c) 1997-2009 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Nicolas Favre-Felix |
| Maintainer: Michael Grunder |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "common.h"
#include "library.h"
#include "redis_array.h"
#include "redis_array_impl.h"
#include
#include
/* Simple macro to detect failure in a RedisArray call */
#define RA_CALL_FAILED(rv, cmd) ( \
(Z_TYPE_P(rv) == IS_FALSE) || \
(Z_TYPE_P(rv) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(rv)) == 0) || \
(Z_TYPE_P(rv) == IS_LONG && Z_LVAL_P(rv) == 0 && !strcasecmp(cmd, "TYPE")) \
)
extern zend_class_entry *redis_ce;
zend_class_entry *redis_array_ce;
#if PHP_VERSION_ID < 80000
#include "redis_array_legacy_arginfo.h"
#else
#include "zend_attributes.h"
#include "redis_array_arginfo.h"
#endif
PHP_MINIT_FUNCTION(redis_array)
{
/* RedisSentinel class */
redis_array_ce = register_class_RedisArray();
redis_array_ce->create_object = create_redis_array_object;
return SUCCESS;
}
static void
redis_array_free(RedisArray *ra)
{
int i;
/* continuum */
if (ra->continuum) {
efree(ra->continuum->points);
efree(ra->continuum);
}
/* Redis objects */
for(i = 0; i< ra->count; i++) {
zval_dtor(&ra->redis[i]);
zend_string_release(ra->hosts[i]);
}
efree(ra->redis);
efree(ra->hosts);
/* delete hash function */
zval_dtor(&ra->z_fun);
/* Distributor */
zval_dtor(&ra->z_dist);
/* Hashing algorithm */
if (ra->algorithm) zend_string_release(ra->algorithm);
/* Delete pur commands */
zend_hash_destroy(ra->pure_cmds);
FREE_HASHTABLE(ra->pure_cmds);
/* Free structure itself */
efree(ra);
}
typedef struct {
RedisArray *ra;
zend_object std;
} redis_array_object;
zend_object_handlers redis_array_object_handlers;
void
free_redis_array_object(zend_object *object)
{
redis_array_object *obj = PHPREDIS_GET_OBJECT(redis_array_object, object);
if (obj->ra) {
if (obj->ra->prev) redis_array_free(obj->ra->prev);
redis_array_free(obj->ra);
}
zend_object_std_dtor(&obj->std);
}
zend_object *
create_redis_array_object(zend_class_entry *ce)
{
redis_array_object *obj = ecalloc(1, sizeof(redis_array_object) + zend_object_properties_size(ce));
obj->ra = NULL;
zend_object_std_init(&obj->std, ce);
object_properties_init(&obj->std, ce);
memcpy(&redis_array_object_handlers, zend_get_std_object_handlers(), sizeof(redis_array_object_handlers));
redis_array_object_handlers.offset = XtOffsetOf(redis_array_object, std);
redis_array_object_handlers.free_obj = free_redis_array_object;
obj->std.handlers = &redis_array_object_handlers;
return &obj->std;
}
/**
* redis_array_get
*/
PHP_REDIS_API RedisArray *
redis_array_get(zval *id)
{
redis_array_object *obj;
if (Z_TYPE_P(id) == IS_OBJECT) {
obj = PHPREDIS_ZVAL_GET_OBJECT(redis_array_object, id);
return obj->ra;
}
return NULL;
}
/* {{{ proto RedisArray RedisArray::__construct()
Public constructor */
PHP_METHOD(RedisArray, __construct)
{
zval *z0, z_fun, z_dist, *zpData, *z_opts = NULL;
RedisArray *ra = NULL;
zend_bool b_index = 0, b_autorehash = 0, b_pconnect = 0, consistent = 0;
HashTable *hPrev = NULL, *hOpts = NULL;
zend_long l_retry_interval = 0;
zend_bool b_lazy_connect = 0;
double d_connect_timeout = 0, read_timeout = 0.0;
zend_string *algorithm = NULL, *user = NULL, *pass = NULL;
redis_array_object *obj;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|a", &z0, &z_opts) == FAILURE) {
RETURN_FALSE;
}
/* Bail if z0 isn't a string or an array.
* Note: WRONG_PARAM_COUNT seems wrong but this is what we have been doing
* for ages so we can't really change it until the next major version.
*/
if (Z_TYPE_P(z0) != IS_ARRAY && Z_TYPE_P(z0) != IS_STRING) {
#if PHP_VERSION_ID < 80000
WRONG_PARAM_COUNT;
#else
zend_argument_type_error(1, "must be of type string|array, %s given", zend_zval_type_name(z0));
RETURN_THROWS();
#endif
}
/* If it's a string we want to load the array from ini information */
if (Z_TYPE_P(z0) == IS_STRING) {
ra = ra_load_array(Z_STRVAL_P(z0));
goto finish;
}
ZVAL_NULL(&z_fun);
ZVAL_NULL(&z_dist);
/* extract options */
if(z_opts) {
hOpts = Z_ARRVAL_P(z_opts);
/* extract previous ring. */
zpData = REDIS_HASH_STR_FIND_STATIC(hOpts, "previous");
if (zpData && Z_TYPE_P(zpData) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(zpData)) > 0) {
hPrev = Z_ARRVAL_P(zpData);
}
REDIS_CONF_AUTH_STATIC(hOpts, "auth", &user, &pass);
REDIS_CONF_ZVAL_STATIC(hOpts, "function", &z_fun, 1, 0);
REDIS_CONF_ZVAL_STATIC(hOpts, "distributor", &z_dist, 1, 0);
REDIS_CONF_STRING_STATIC(hOpts, "algorithm", &algorithm);
REDIS_CONF_ZEND_BOOL_STATIC(hOpts, "index", &b_index);
REDIS_CONF_ZEND_BOOL_STATIC(hOpts, "autorehash", &b_autorehash);
REDIS_CONF_ZEND_BOOL_STATIC(hOpts, "pconnect", &b_pconnect);
REDIS_CONF_LONG_STATIC(hOpts, "retry_interval", &l_retry_interval);
REDIS_CONF_ZEND_BOOL_STATIC(hOpts, "lazy_connect", &b_lazy_connect);
REDIS_CONF_ZEND_BOOL_STATIC(hOpts, "consistent", &consistent);
REDIS_CONF_DOUBLE_STATIC(hOpts, "connect_timeout", &d_connect_timeout);
REDIS_CONF_DOUBLE_STATIC(hOpts, "read_timeout", &read_timeout);
}
ra = ra_make_array(Z_ARRVAL_P(z0), &z_fun, &z_dist, hPrev, b_index,
b_pconnect, l_retry_interval, b_lazy_connect,
d_connect_timeout, read_timeout, consistent,
algorithm, user, pass);
if (algorithm) zend_string_release(algorithm);
if (user) zend_string_release(user);
if (pass) zend_string_release(pass);
zval_dtor(&z_dist);
zval_dtor(&z_fun);
finish:
if(ra) {
ra->auto_rehash = b_autorehash;
ra->connect_timeout = d_connect_timeout;
if(ra->prev) ra->prev->auto_rehash = b_autorehash;
obj = PHPREDIS_ZVAL_GET_OBJECT(redis_array_object, getThis());
obj->ra = ra;
}
}
static void
ra_forward_call(INTERNAL_FUNCTION_PARAMETERS, RedisArray *ra, const char *cmd,
int cmd_len, zval *z_args, zval *z_new_target)
{
zval z_fun, *redis_inst, *z_callargs, *zp_tmp;
char *key = NULL; /* set to avoid "unused-but-set-variable" */
int i, key_len = 0, argc;
HashTable *h_args;
zend_bool b_write_cmd = 0;
h_args = Z_ARRVAL_P(z_args);
if ((argc = zend_hash_num_elements(h_args)) == 0) {
RETURN_FALSE;
}
if(ra->z_multi_exec) {
redis_inst = ra->z_multi_exec; /* we already have the instance */
} else {
/* extract key and hash it. */
if ((zp_tmp = zend_hash_index_find(h_args, 0)) == NULL || Z_TYPE_P(zp_tmp) != IS_STRING) {
php_error_docref(NULL, E_ERROR, "Could not find key");
RETURN_FALSE;
}
key = Z_STRVAL_P(zp_tmp);
key_len = Z_STRLEN_P(zp_tmp);
/* find node */
redis_inst = ra_find_node(ra, key, key_len, NULL);
if(!redis_inst) {
php_error_docref(NULL, E_ERROR, "Could not find any redis servers for this key.");
RETURN_FALSE;
}
}
/* pass call through */
ZVAL_STRINGL(&z_fun, cmd, cmd_len); /* method name */
z_callargs = ecalloc(argc, sizeof(*z_callargs));
/* copy args to array */
i = 0;
ZEND_HASH_FOREACH_VAL(h_args, zp_tmp) {
ZVAL_ZVAL(&z_callargs[i], zp_tmp, 1, 0);
i++;
} ZEND_HASH_FOREACH_END();
/* multi/exec */
if(ra->z_multi_exec) {
call_user_function(&redis_ce->function_table, ra->z_multi_exec, &z_fun, return_value, argc, z_callargs);
zval_dtor(return_value);
zval_dtor(&z_fun);
for (i = 0; i < argc; ++i) {
zval_dtor(&z_callargs[i]);
}
efree(z_callargs);
RETURN_ZVAL(getThis(), 1, 0);
}
/* check if write cmd */
b_write_cmd = ra_is_write_cmd(ra, cmd, cmd_len);
/* CALL! */
if(ra->index && b_write_cmd) {
/* add MULTI + SADD */
ra_index_multi(redis_inst, MULTI);
/* call using discarded temp value and extract exec results after. */
call_user_function(&redis_ce->function_table, redis_inst, &z_fun, return_value, argc, z_callargs);
zval_dtor(return_value);
/* add keys to index. */
ra_index_key(key, key_len, redis_inst);
/* call EXEC */
ra_index_exec(redis_inst, return_value, 0);
} else { /* call directly through. */
call_user_function(&redis_ce->function_table, redis_inst, &z_fun, return_value, argc, z_callargs);
if (!b_write_cmd) {
/* check if we have an error. */
if (ra->prev && RA_CALL_FAILED(return_value, cmd)) { /* there was an error reading, try with prev ring. */
/* Free previous return value */
zval_dtor(return_value);
/* ERROR, FALLBACK TO PREVIOUS RING and forward a reference to the first redis instance we were looking at. */
ra_forward_call(INTERNAL_FUNCTION_PARAM_PASSTHRU, ra->prev, cmd, cmd_len, z_args, z_new_target ? z_new_target : redis_inst);
}
/* Autorehash if the key was found on the previous node if this is a read command and auto rehashing is on */
if (ra->auto_rehash && z_new_target && !RA_CALL_FAILED(return_value, cmd)) { /* move key from old ring to new ring */
ra_move_key(key, key_len, redis_inst, z_new_target);
}
}
}
/* cleanup */
zval_dtor(&z_fun);
for (i = 0; i < argc; ++i) {
zval_dtor(&z_callargs[i]);
}
efree(z_callargs);
}
PHP_METHOD(RedisArray, __call)
{
zval *object;
RedisArray *ra;
zval *z_args;
char *cmd;
size_t cmd_len;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Osa",
&object, redis_array_ce, &cmd, &cmd_len, &z_args) == FAILURE) {
RETURN_FALSE;
}
if ((ra = redis_array_get(object)) == NULL) {
RETURN_FALSE;
}
ra_forward_call(INTERNAL_FUNCTION_PARAM_PASSTHRU, ra, cmd, cmd_len, z_args, NULL);
}
PHP_METHOD(RedisArray, _hosts)
{
zval *object;
int i;
RedisArray *ra;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
&object, redis_array_ce) == FAILURE) {
RETURN_FALSE;
}
if ((ra = redis_array_get(object)) == NULL) {
RETURN_FALSE;
}
array_init(return_value);
for(i = 0; i < ra->count; ++i) {
add_next_index_stringl(return_value, ZSTR_VAL(ra->hosts[i]), ZSTR_LEN(ra->hosts[i]));
}
}
PHP_METHOD(RedisArray, _target)
{
zval *object;
RedisArray *ra;
char *key;
size_t key_len;
zval *redis_inst;
int i;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os",
&object, redis_array_ce, &key, &key_len) == FAILURE) {
RETURN_FALSE;
}
if ((ra = redis_array_get(object)) == NULL) {
RETURN_FALSE;
}
redis_inst = ra_find_node(ra, key, key_len, &i);
if(redis_inst) {
RETURN_STRINGL(ZSTR_VAL(ra->hosts[i]), ZSTR_LEN(ra->hosts[i]));
} else {
RETURN_NULL();
}
}
PHP_METHOD(RedisArray, _instance)
{
zval *object;
RedisArray *ra;
zend_string *host;
zval *z_redis;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "OS",
&object, redis_array_ce, &host) == FAILURE) {
RETURN_FALSE;
}
if ((ra = redis_array_get(object)) == NULL) {
RETURN_FALSE;
}
if ((z_redis = ra_find_node_by_name(ra, host)) == NULL) {
RETURN_NULL();
}
RETURN_ZVAL(z_redis, 1, 0);
}
PHP_METHOD(RedisArray, _function)
{
zval *object;
RedisArray *ra;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
&object, redis_array_ce) == FAILURE) {
RETURN_FALSE;
}
if ((ra = redis_array_get(object)) == NULL) {
RETURN_FALSE;
}
RETURN_ZVAL(&ra->z_fun, 1, 0);
}
PHP_METHOD(RedisArray, _distributor)
{
zval *object;
RedisArray *ra;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
&object, redis_array_ce) == FAILURE) {
RETURN_FALSE;
}
if ((ra = redis_array_get(object)) == NULL) {
RETURN_FALSE;
}
RETURN_ZVAL(&ra->z_dist, 1, 0);
}
PHP_METHOD(RedisArray, _rehash)
{
zval *object;
RedisArray *ra;
zend_fcall_info z_cb = {0};
zend_fcall_info_cache z_cb_cache = {0};
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|f",
&object, redis_array_ce, &z_cb, &z_cb_cache) == FAILURE) {
RETURN_FALSE;
}
if ((ra = redis_array_get(object)) == NULL) {
RETURN_FALSE;
}
if (ZEND_NUM_ARGS() == 0) {
ra_rehash(ra, NULL, NULL);
} else {
ra_rehash(ra, &z_cb, &z_cb_cache);
}
}
PHP_METHOD(RedisArray, _continuum)
{
int i;
zval *object, z_ret;
RedisArray *ra;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
&object, redis_array_ce) == FAILURE) {
RETURN_FALSE;
}
if ((ra = redis_array_get(object)) == NULL) {
RETURN_FALSE;
}
array_init(return_value);
if (ra->continuum) {
for (i = 0; i < ra->continuum->nb_points; ++i) {
array_init(&z_ret);
add_assoc_long(&z_ret, "index", ra->continuum->points[i].index);
add_assoc_long(&z_ret, "value", ra->continuum->points[i].value);
add_next_index_zval(return_value, &z_ret);
}
}
}
static void
multihost_distribute_call(RedisArray *ra, zval *return_value, zval *z_fun, int argc, zval *argv)
{
zval z_tmp;
int i;
/* Init our array return */
array_init(return_value);
/* Iterate our RedisArray nodes */
for (i = 0; i < ra->count; ++i) {
/* Call each node in turn */
call_user_function(&redis_array_ce->function_table, &ra->redis[i], z_fun, &z_tmp, argc, argv);
/* Add the result for this host */
add_assoc_zval_ex(return_value, ZSTR_VAL(ra->hosts[i]), ZSTR_LEN(ra->hosts[i]), &z_tmp);
}
}
static void
multihost_distribute(INTERNAL_FUNCTION_PARAMETERS, const char *method_name)
{
zval *object, z_fun;
RedisArray *ra;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
&object, redis_array_ce) == FAILURE) {
RETURN_FALSE;
}
if ((ra = redis_array_get(object)) == NULL) {
RETURN_FALSE;
}
/* prepare call */
ZVAL_STRING(&z_fun, method_name);
multihost_distribute_call(ra, return_value, &z_fun, 0, NULL);
zval_dtor(&z_fun);
}
static void
multihost_distribute_flush(INTERNAL_FUNCTION_PARAMETERS, const char *method_name)
{
zval *object, z_fun, z_args[1];
zend_bool async = 0;
RedisArray *ra;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|b",
&object, redis_array_ce, &async) == FAILURE) {
RETURN_FALSE;
}
if ((ra = redis_array_get(object)) == NULL) {
RETURN_FALSE;
}
/* prepare call */
ZVAL_STRING(&z_fun, method_name);
ZVAL_BOOL(&z_args[0], async);
multihost_distribute_call(ra, return_value, &z_fun, 1, z_args);
zval_dtor(&z_fun);
}
PHP_METHOD(RedisArray, info)
{
multihost_distribute(INTERNAL_FUNCTION_PARAM_PASSTHRU, "INFO");
}
PHP_METHOD(RedisArray, ping)
{
multihost_distribute(INTERNAL_FUNCTION_PARAM_PASSTHRU, "PING");
}
PHP_METHOD(RedisArray, flushdb)
{
multihost_distribute_flush(INTERNAL_FUNCTION_PARAM_PASSTHRU, "FLUSHDB");
}
PHP_METHOD(RedisArray, flushall)
{
multihost_distribute_flush(INTERNAL_FUNCTION_PARAM_PASSTHRU, "FLUSHALL");
}
PHP_METHOD(RedisArray, save)
{
multihost_distribute(INTERNAL_FUNCTION_PARAM_PASSTHRU, "SAVE");
}
PHP_METHOD(RedisArray, bgsave)
{
multihost_distribute(INTERNAL_FUNCTION_PARAM_PASSTHRU, "BGSAVE");
}
PHP_METHOD(RedisArray, keys)
{
zval *object, z_fun, z_args[1];
RedisArray *ra;
char *pattern;
size_t pattern_len;
/* Make sure the prototype is correct */
if(zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os",
&object, redis_array_ce, &pattern, &pattern_len) == FAILURE)
{
RETURN_FALSE;
}
/* Make sure we can grab our RedisArray object */
if ((ra = redis_array_get(object)) == NULL) {
RETURN_FALSE;
}
/* Set up our function call (KEYS) */
ZVAL_STRINGL(&z_fun, "KEYS", 4);
/* We will be passing with one string argument (the pattern) */
ZVAL_STRINGL(z_args, pattern, pattern_len);
multihost_distribute_call(ra, return_value, &z_fun, 1, z_args);
zval_dtor(&z_args[0]);
zval_dtor(&z_fun);
}
PHP_METHOD(RedisArray, getOption)
{
zval *object, z_fun, z_args[1];
RedisArray *ra;
zend_long opt;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol",
&object, redis_array_ce, &opt) == FAILURE) {
RETURN_FALSE;
}
if ((ra = redis_array_get(object)) == NULL) {
RETURN_FALSE;
}
/* prepare call */
ZVAL_STRINGL(&z_fun, "getOption", 9);
/* copy arg */
ZVAL_LONG(&z_args[0], opt);
multihost_distribute_call(ra, return_value, &z_fun, 1, z_args);
zval_dtor(&z_fun);
}
PHP_METHOD(RedisArray, setOption)
{
zval *object, z_fun, z_args[2];
RedisArray *ra;
zend_long opt;
char *val_str;
size_t val_len;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ols",
&object, redis_array_ce, &opt, &val_str, &val_len) == FAILURE) {
RETURN_FALSE;
}
if ((ra = redis_array_get(object)) == NULL) {
RETURN_FALSE;
}
/* prepare call */
ZVAL_STRINGL(&z_fun, "setOption", 9);
/* copy args */
ZVAL_LONG(&z_args[0], opt);
ZVAL_STRINGL(&z_args[1], val_str, val_len);
multihost_distribute_call(ra, return_value, &z_fun, 2, z_args);
zval_dtor(&z_args[1]);
zval_dtor(&z_fun);
}
PHP_METHOD(RedisArray, select)
{
zval *object, z_fun, z_args[1];
RedisArray *ra;
zend_long opt;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol",
&object, redis_array_ce, &opt) == FAILURE) {
RETURN_FALSE;
}
if ((ra = redis_array_get(object)) == NULL) {
RETURN_FALSE;
}
/* prepare call */
ZVAL_STRINGL(&z_fun, "select", 6);
/* copy args */
ZVAL_LONG(&z_args[0], opt);
multihost_distribute_call(ra, return_value, &z_fun, 1, z_args);
zval_dtor(&z_fun);
}
#define HANDLE_MULTI_EXEC(ra, cmd, cmdlen) do { \
if (ra && ra->z_multi_exec) { \
int i, num_varargs; \
zval *varargs = NULL, z_arg_array; \
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O*", \
&object, redis_array_ce, &varargs, &num_varargs) == FAILURE) { \
RETURN_FALSE;\
} \
/* copy all args into a zval hash table */\
array_init(&z_arg_array); \
for (i = 0; i < num_varargs; i++) { \
zval z_tmp; \
ZVAL_ZVAL(&z_tmp, &varargs[i], 1, 0); \
add_next_index_zval(&z_arg_array, &z_tmp); \
} \
/* call */\
ra_forward_call(INTERNAL_FUNCTION_PARAM_PASSTHRU, ra, cmd, cmdlen, &z_arg_array, NULL); \
zval_dtor(&z_arg_array); \
return; \
} \
} while(0)
/* MGET will distribute the call to several nodes and regroup the values. */
PHP_METHOD(RedisArray, mget)
{
zval *object, *z_keys, *data, z_ret, *z_cur, z_tmp_array, z_fun, z_arg, **argv;
int i, j, n, *pos, argc, *argc_each;
HashTable *h_keys;
RedisArray *ra;
if ((ra = redis_array_get(getThis())) == NULL) {
RETURN_FALSE;
}
/* Multi/exec support */
HANDLE_MULTI_EXEC(ra, "MGET", sizeof("MGET") - 1);
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oa",
&object, redis_array_ce, &z_keys) == FAILURE) {
RETURN_FALSE;
}
/* init data structures */
h_keys = Z_ARRVAL_P(z_keys);
if ((argc = zend_hash_num_elements(h_keys)) == 0) {
RETURN_FALSE;
}
argv = ecalloc(argc, sizeof(*argv));
pos = ecalloc(argc, sizeof(*pos));
argc_each = ecalloc(ra->count, sizeof(*argc_each));
/* associate each key to a redis node */
i = 0;
ZEND_HASH_FOREACH_VAL(h_keys, data) {
/* If we need to represent a long key as a string */
unsigned int key_len;
char kbuf[40], *key_lookup;
/* Handle the possibility that we're a reference */
ZVAL_DEREF(data);
/* Convert to a string for hash lookup if it isn't one */
if (Z_TYPE_P(data) == IS_STRING) {
key_len = Z_STRLEN_P(data);
key_lookup = Z_STRVAL_P(data);
} else if (Z_TYPE_P(data) == IS_LONG) {
key_len = snprintf(kbuf, sizeof(kbuf), ZEND_LONG_FMT, Z_LVAL_P(data));
key_lookup = (char*)kbuf;
} else {
/* phpredis proper can only use string or long keys, so restrict to that here */
php_error_docref(NULL, E_ERROR, "MGET: all keys must be strings or longs");
RETVAL_FALSE;
goto cleanup;
}
/* Find our node */
if (ra_find_node(ra, key_lookup, key_len, &pos[i]) == NULL) {
RETVAL_FALSE;
goto cleanup;
}
argc_each[pos[i]]++; /* count number of keys per node */
argv[i++] = data;
} ZEND_HASH_FOREACH_END();
/* prepare call */
array_init(&z_tmp_array);
ZVAL_STRINGL(&z_fun, "MGET", sizeof("MGET") - 1);
/* calls */
for(n = 0; n < ra->count; ++n) { /* for each node */
/* We don't even need to make a call to this node if no keys go there */
if(!argc_each[n]) continue;
/* copy args for MGET call on node. */
array_init(&z_arg);
for(i = 0; i < argc; ++i) {
if (pos[i] == n) {
ZVAL_ZVAL(&z_ret, argv[i], 1, 0);
add_next_index_zval(&z_arg, &z_ret);
}
}
/* call MGET on the node */
call_user_function(&redis_ce->function_table, &ra->redis[n], &z_fun, &z_ret, 1, &z_arg);
/* cleanup args array */
zval_dtor(&z_arg);
/* Error out if we didn't get a proper response */
if (Z_TYPE(z_ret) != IS_ARRAY) {
/* cleanup */
zval_dtor(&z_ret);
zval_dtor(&z_tmp_array);
RETVAL_FALSE;
goto cleanup;
}
for(i = 0, j = 0; i < argc; ++i) {
if (pos[i] != n || (z_cur = zend_hash_index_find(Z_ARRVAL(z_ret), j++)) == NULL) continue;
ZVAL_ZVAL(&z_arg, z_cur, 1, 0);
add_index_zval(&z_tmp_array, i, &z_arg);
}
zval_dtor(&z_ret);
}
zval_dtor(&z_fun);
array_init(return_value);
/* copy temp array in the right order to return_value */
for(i = 0; i < argc; ++i) {
if ((z_cur = zend_hash_index_find(Z_ARRVAL(z_tmp_array), i)) == NULL) continue;
ZVAL_ZVAL(&z_arg, z_cur, 1, 0);
add_next_index_zval(return_value, &z_arg);
}
/* cleanup */
zval_dtor(&z_tmp_array);
cleanup:
efree(argv);
efree(pos);
efree(argc_each);
}
/* MSET will distribute the call to several nodes and regroup the values. */
PHP_METHOD(RedisArray, mset)
{
zval *object, *z_keys, z_argarray, *data, z_fun, z_ret, **argv;
int i = 0, n, *pos, argc, *argc_each, key_len;
RedisArray *ra;
HashTable *h_keys;
char *key, kbuf[40];
zend_string **keys, *zkey;
zend_ulong idx;
if ((ra = redis_array_get(getThis())) == NULL) {
RETURN_FALSE;
}
/* Multi/exec support */
HANDLE_MULTI_EXEC(ra, "MSET", sizeof("MSET") - 1);
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oa",
&object, redis_array_ce, &z_keys) == FAILURE)
{
RETURN_FALSE;
}
/* init data structures */
h_keys = Z_ARRVAL_P(z_keys);
if ((argc = zend_hash_num_elements(h_keys)) == 0) {
RETURN_FALSE;
}
argv = ecalloc(argc, sizeof(*argv));
pos = ecalloc(argc, sizeof(*pos));
keys = ecalloc(argc, sizeof(*keys));
argc_each = ecalloc(ra->count, sizeof(*argc_each));
/* associate each key to a redis node */
ZEND_HASH_FOREACH_KEY_VAL(h_keys, idx, zkey, data) {
/* If the key isn't a string, make a string representation of it */
if (zkey) {
key_len = ZSTR_LEN(zkey);
key = ZSTR_VAL(zkey);
} else {
key_len = snprintf(kbuf, sizeof(kbuf), ZEND_ULONG_FMT, idx);
key = kbuf;
}
if (ra_find_node(ra, key, (int)key_len, &pos[i]) == NULL) {
for (n = 0; n < i; ++n) {
zend_string_release(keys[n]);
}
efree(keys);
efree(argv);
efree(pos);
efree(argc_each);
RETURN_FALSE;
}
argc_each[pos[i]]++; /* count number of keys per node */
keys[i] = zkey ? zend_string_copy(zkey) : zend_string_init(key, key_len, 0);
argv[i] = data;
i++;
} ZEND_HASH_FOREACH_END();
/* prepare call */
ZVAL_STRINGL(&z_fun, "MSET", sizeof("MSET") - 1);
/* calls */
for (n = 0; n < ra->count; ++n) { /* for each node */
/* We don't even need to make a call to this node if no keys go there */
if(!argc_each[n]) continue;
int found = 0;
/* copy args */
array_init(&z_argarray);
for(i = 0; i < argc; ++i) {
if(pos[i] != n) continue;
if (argv[i] == NULL) {
ZVAL_NULL(&z_ret);
} else {
ZVAL_ZVAL(&z_ret, argv[i], 1, 0);
}
add_assoc_zval_ex(&z_argarray, ZSTR_VAL(keys[i]), ZSTR_LEN(keys[i]), &z_ret);
found++;
}
if(!found) {
zval_dtor(&z_argarray);
continue; /* don't run empty MSETs */
}
if(ra->index) { /* add MULTI */
ra_index_multi(&ra->redis[n], MULTI);
call_user_function(&redis_ce->function_table, &ra->redis[n], &z_fun, &z_ret, 1, &z_argarray);
ra_index_keys(&z_argarray, &ra->redis[n]); /* use SADD to add keys to node index */
ra_index_exec(&ra->redis[n], NULL, 0); /* run EXEC */
} else {
call_user_function(&redis_ce->function_table, &ra->redis[n], &z_fun, &z_ret, 1, &z_argarray);
}
zval_dtor(&z_argarray);
zval_dtor(&z_ret);
}
zval_dtor(&z_fun);
/* Free any keys that we needed to allocate memory for, because they weren't strings */
for(i = 0; i < argc; i++) {
zend_string_release(keys[i]);
}
/* cleanup */
efree(keys);
efree(argv);
efree(pos);
efree(argc_each);
RETURN_TRUE;
}
/* Generic handler for DEL or UNLINK which behave identically to phpredis */
static void
ra_generic_del(INTERNAL_FUNCTION_PARAMETERS, char *kw, int kw_len)
{
zval *object, z_keys, z_fun, *data, z_ret, *z_args, **argv;
int i, n, *pos, argc = ZEND_NUM_ARGS(), *argc_each, free_zkeys = 0;
HashTable *h_keys;
RedisArray *ra;
long total = 0;
if ((ra = redis_array_get(getThis())) == NULL) {
RETURN_FALSE;
}
/* Multi/exec support */
HANDLE_MULTI_EXEC(ra, kw, kw_len);
/* get all args in z_args */
z_args = ecalloc(argc, sizeof(*z_args));
if (zend_get_parameters_array(ht, argc, z_args) == FAILURE) {
efree(z_args);
RETURN_FALSE;
}
/* if single array arg, point z_keys to it. */
if (argc == 1 && Z_TYPE(z_args[0]) == IS_ARRAY) {
z_keys = z_args[0];
} else {
/* copy all elements to z_keys */
array_init(&z_keys);
for (i = 0; i < argc; ++i) {
ZVAL_ZVAL(&z_ret, &z_args[i], 1, 0);
add_next_index_zval(&z_keys, &z_ret);
}
free_zkeys = 1;
}
/* init data structures */
h_keys = Z_ARRVAL(z_keys);
if ((argc = zend_hash_num_elements(h_keys)) == 0) {
if (free_zkeys) zval_dtor(&z_keys);
efree(z_args);
RETURN_FALSE;
}
argv = ecalloc(argc, sizeof(*argv));
pos = ecalloc(argc, sizeof(*pos));
argc_each = ecalloc(ra->count, sizeof(*argc_each));
/* associate each key to a redis node */
i = 0;
ZEND_HASH_FOREACH_VAL(h_keys, data) {
if (Z_TYPE_P(data) != IS_STRING) {
php_error_docref(NULL, E_ERROR, "DEL: all keys must be string.");
RETVAL_FALSE;
goto cleanup;
}
if (ra_find_node(ra, Z_STRVAL_P(data), Z_STRLEN_P(data), &pos[i]) == NULL) {
RETVAL_FALSE;
goto cleanup;
}
argc_each[pos[i]]++; /* count number of keys per node */
argv[i++] = data;
} ZEND_HASH_FOREACH_END();
/* prepare call */
ZVAL_STRINGL(&z_fun, kw, kw_len);
/* calls */
for(n = 0; n < ra->count; ++n) { /* for each node */
/* We don't even need to make a call to this node if no keys go there */
if(!argc_each[n]) continue;
int found = 0;
zval z_argarray;
/* copy args */
array_init(&z_argarray);
for(i = 0; i < argc; ++i) {
if (pos[i] == n) {
ZVAL_ZVAL(&z_ret, argv[i], 1, 0);
add_next_index_zval(&z_argarray, &z_ret);
found++;
}
}
if(!found) { /* don't run empty DEL or UNLINK commands */
zval_dtor(&z_argarray);
continue;
}
if(ra->index) { /* add MULTI */
ra_index_multi(&ra->redis[n], MULTI);
call_user_function(&redis_ce->function_table, &ra->redis[n], &z_fun, &z_ret, 1, &z_argarray);
ra_index_del(&z_argarray, &ra->redis[n]); /* use SREM to remove keys from node index */
ra_index_exec(&ra->redis[n], &z_ret, 0); /* run EXEC */
} else {
call_user_function(&redis_ce->function_table, &ra->redis[n], &z_fun, &z_ret, 1, &z_argarray);
}
total += Z_LVAL(z_ret); /* increment total */
zval_dtor(&z_argarray);
zval_dtor(&z_ret);
}
zval_dtor(&z_fun);
RETVAL_LONG(total);
cleanup:
efree(argv);
efree(pos);
efree(argc_each);
if(free_zkeys) {
zval_dtor(&z_keys);
}
efree(z_args);
}
/* DEL will distribute the call to several nodes and regroup the values. */
PHP_METHOD(RedisArray, del)
{
ra_generic_del(INTERNAL_FUNCTION_PARAM_PASSTHRU, "DEL", sizeof("DEL")-1);
}
PHP_METHOD(RedisArray, unlink) {
ra_generic_del(INTERNAL_FUNCTION_PARAM_PASSTHRU, "UNLINK", sizeof("UNLINK") - 1);
}
static void
ra_generic_scan_cmd(INTERNAL_FUNCTION_PARAMETERS, const char *kw, int kw_len)
{
RedisArray *ra;
zend_string *key, *pattern = NULL;
zval *object, *redis_inst, *z_iter, z_fun, z_args[4];
zend_long count = 0;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "OSz/|S!l",
&object, redis_array_ce, &key, &z_iter, &pattern, &count) == FAILURE) {
RETURN_FALSE;
}
if ((ra = redis_array_get(object)) == NULL) {
RETURN_FALSE;
}
if ((redis_inst = ra_find_node(ra, ZSTR_VAL(key), ZSTR_LEN(key), NULL)) == NULL) {
php_error_docref(NULL, E_ERROR, "Could not find any redis servers for this key.");
RETURN_FALSE;
}
ZVAL_STR(&z_args[0], key);
ZVAL_NEW_REF(&z_args[1], z_iter);
if (pattern) ZVAL_STR(&z_args[2], pattern);
ZVAL_LONG(&z_args[3], count);
ZVAL_STRINGL(&z_fun, kw, kw_len);
call_user_function(&redis_ce->function_table, redis_inst, &z_fun, return_value, ZEND_NUM_ARGS(), z_args);
zval_dtor(&z_fun);
ZVAL_ZVAL(z_iter, &z_args[1], 0, 1);
}
PHP_METHOD(RedisArray, hscan)
{
ra_generic_scan_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "HSCAN", sizeof("HSCAN") - 1);
}
PHP_METHOD(RedisArray, sscan)
{
ra_generic_scan_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "SSCAN", sizeof("SSCAN") - 1);
}
PHP_METHOD(RedisArray, zscan)
{
ra_generic_scan_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "ZSCAN", sizeof("ZSCAN") - 1);
}
PHP_METHOD(RedisArray, scan)
{
RedisArray *ra;
zend_string *host, *pattern = NULL;
zval *object, *redis_inst, *z_iter, z_fun, z_args[3];
zend_long count = 0;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oz/S|S!l",
&object, redis_array_ce, &z_iter, &host, &pattern, &count) == FAILURE) {
RETURN_FALSE;
}
if ((ra = redis_array_get(object)) == NULL) {
RETURN_FALSE;
}
if ((redis_inst = ra_find_node_by_name(ra, host)) == NULL) {
RETURN_FALSE;
}
ZVAL_NEW_REF(&z_args[0], z_iter);
if (pattern) ZVAL_STR(&z_args[1], pattern);
ZVAL_LONG(&z_args[2], count);
ZVAL_STRING(&z_fun, "SCAN");
call_user_function(&redis_ce->function_table, redis_inst, &z_fun, return_value, ZEND_NUM_ARGS() - 1, z_args);
zval_dtor(&z_fun);
ZVAL_ZVAL(z_iter, &z_args[0], 0, 1);
}
PHP_METHOD(RedisArray, multi)
{
zval *object;
RedisArray *ra;
zval *z_redis;
zend_string *host;
zend_long multi_value = MULTI;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "OS|l",
&object, redis_array_ce, &host, &multi_value) == FAILURE) {
RETURN_FALSE;
}
if ((ra = redis_array_get(object)) == NULL) {
RETURN_FALSE;
}
/* find node */
if ((z_redis = ra_find_node_by_name(ra, host)) == NULL) {
RETURN_FALSE;
}
if(multi_value != MULTI && multi_value != PIPELINE) {
RETURN_FALSE;
}
/* save multi object */
ra->z_multi_exec = z_redis;
/* switch redis instance to multi/exec mode. */
ra_index_multi(z_redis, multi_value);
/* return this. */
RETURN_ZVAL(object, 1, 0);
}
PHP_METHOD(RedisArray, exec)
{
zval *object;
RedisArray *ra;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
&object, redis_array_ce) == FAILURE) {
RETURN_FALSE;
}
if ((ra = redis_array_get(object)) == NULL || !ra->z_multi_exec) {
RETURN_FALSE;
}
/* switch redis instance out of multi/exec mode. */
ra_index_exec(ra->z_multi_exec, return_value, 1);
/* remove multi object */
ra->z_multi_exec = NULL;
}
PHP_METHOD(RedisArray, discard)
{
zval *object;
RedisArray *ra;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
&object, redis_array_ce) == FAILURE) {
RETURN_FALSE;
}
if ((ra = redis_array_get(object)) == NULL || !ra->z_multi_exec) {
RETURN_FALSE;
}
/* switch redis instance out of multi/exec mode. */
ra_index_discard(ra->z_multi_exec, return_value);
/* remove multi object */
ra->z_multi_exec = NULL;
}
PHP_METHOD(RedisArray, unwatch)
{
zval *object;
RedisArray *ra;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
&object, redis_array_ce) == FAILURE) {
RETURN_FALSE;
}
if ((ra = redis_array_get(object)) == NULL || !ra->z_multi_exec) {
RETURN_FALSE;
}
/* unwatch keys, stay in multi/exec mode. */
ra_index_unwatch(ra->z_multi_exec, return_value);
}
redis-6.0.2/redis_array.h 0000644 0001750 0000012 00000002427 14515245367 016102 0 ustar pyatsukhnenko wheel #ifndef REDIS_ARRAY_H
#define REDIS_ARRAY_H
#if (defined(_MSC_VER) && _MSC_VER <= 1920)
#include "win32/php_stdint.h"
#else
#include
#endif
#include "common.h"
typedef struct {
uint32_t value;
int index;
} ContinuumPoint;
typedef struct {
size_t nb_points;
ContinuumPoint *points;
} Continuum;
typedef struct RedisArray_ {
int count;
zend_string **hosts; /* array of host:port strings */
zval *redis; /* array of Redis instances */
zval *z_multi_exec; /* Redis instance to be used in multi-exec */
zend_bool index; /* use per-node index */
zend_bool auto_rehash; /* migrate keys on read operations */
zend_bool pconnect; /* should we use pconnect */
zval z_fun; /* key extractor, callable */
zval z_dist; /* key distributor, callable */
zend_string *algorithm; /* key hashing algorithm name */
HashTable *pure_cmds; /* hash table */
double connect_timeout; /* socket connect timeout */
double read_timeout; /* socket read timeout */
Continuum *continuum;
struct RedisArray_ *prev;
} RedisArray;
extern zend_class_entry *redis_array_ce;
extern PHP_MINIT_FUNCTION(redis_array);
extern zend_object *create_redis_array_object(zend_class_entry *ce);
#endif
redis-6.0.2/redis_array.stub.php 0000644 0001750 0000012 00000004002 14515245367 017405 0 ustar pyatsukhnenko wheel |
| Maintainer: Michael Grunder |
+----------------------------------------------------------------------+
*/
#include "redis_array_impl.h"
#include "php_redis.h"
#include "library.h"
#include "php_variables.h"
#include "SAPI.h"
#include "ext/standard/url.h"
#include "ext/standard/crc32.h"
#include "ext/standard/md5.h"
#include "ext/hash/php_hash.h"
#define PHPREDIS_INDEX_NAME "__phpredis_array_index__"
extern zend_class_entry *redis_ce;
static RedisArray *
ra_load_hosts(RedisArray *ra, HashTable *hosts, zend_string *user,
zend_string *pass, long retry_interval, zend_bool b_lazy_connect)
{
int i = 0, host_len;
char *host, *p;
short port;
zval *zpData;
redis_object *redis;
/* init connections */
ZEND_HASH_FOREACH_VAL(hosts, zpData) {
if (Z_TYPE_P(zpData) != IS_STRING) {
return NULL;
}
/* default values */
host = Z_STRVAL_P(zpData);
host_len = Z_STRLEN_P(zpData);
ra->hosts[i] = zend_string_init(host, host_len, 0);
port = 6379;
if((p = strrchr(host, ':'))) { /* found port */
host_len = p - host;
port = (short)atoi(p+1);
} else if(strchr(host,'/') != NULL) { /* unix socket */
port = -1;
}
/* create Redis object */
object_init_ex(&ra->redis[i], redis_ce);
redis = PHPREDIS_ZVAL_GET_OBJECT(redis_object, &ra->redis[i]);
/* create socket */
redis->sock = redis_sock_create(host, host_len, port, ra->connect_timeout,
ra->read_timeout, ra->pconnect, NULL,
retry_interval);
redis_sock_set_auth(redis->sock, user, pass);
if (!b_lazy_connect) {
if (redis_sock_server_open(redis->sock) < 0) {
ra->count = ++i;
return NULL;
}
}
ra->count = ++i;
} ZEND_HASH_FOREACH_END();
return ra;
}
/* List pure functions */
void
ra_init_function_table(RedisArray *ra)
{
ALLOC_HASHTABLE(ra->pure_cmds);
zend_hash_init(ra->pure_cmds, 0, NULL, NULL, 0);
zend_hash_str_update_ptr(ra->pure_cmds, "EXISTS", sizeof("EXISTS") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "GET", sizeof("GET") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "GETBIT", sizeof("GETBIT") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "GETRANGE", sizeof("GETRANGE") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "HEXISTS", sizeof("HEXISTS") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "HGET", sizeof("HGET") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "HGETALL", sizeof("HGETALL") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "HKEYS", sizeof("HKEYS") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "HLEN", sizeof("HLEN") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "HMGET", sizeof("HMGET") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "HVALS", sizeof("HVALS") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "LINDEX", sizeof("LINDEX") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "LLEN", sizeof("LLEN") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "LRANGE", sizeof("LRANGE") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "OBJECT", sizeof("OBJECT") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "SCARD", sizeof("SCARD") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "SDIFF", sizeof("SDIFF") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "SINTER", sizeof("SINTER") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "SISMEMBER", sizeof("SISMEMBER") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "SMEMBERS", sizeof("SMEMBERS") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "SRANDMEMBER", sizeof("SRANDMEMBER") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "STRLEN", sizeof("STRLEN") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "SUNION", sizeof("SUNION") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "TYPE", sizeof("TYPE") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "ZCARD", sizeof("ZCARD") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "ZCOUNT", sizeof("ZCOUNT") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "ZRANGE", sizeof("ZRANGE") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "ZRANK", sizeof("ZRANK") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "ZREVRANGE", sizeof("ZREVRANGE") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "ZREVRANGEBYSCORE", sizeof("ZREVRANGEBYSCORE") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "ZREVRANK", sizeof("ZREVRANK") - 1, NULL);
zend_hash_str_update_ptr(ra->pure_cmds, "ZSCORE", sizeof("ZSCORE") - 1, NULL);
}
static int
ra_find_name(const char *name) {
const char *ini_names, *p, *next;
/* php_printf("Loading redis array with name=[%s]\n", name); */
ini_names = INI_STR("redis.arrays.names");
for(p = ini_names; p;) {
next = strchr(p, ',');
if(next) {
if(strncmp(p, name, next - p) == 0) {
return 1;
}
} else {
if(strcmp(p, name) == 0) {
return 1;
}
break;
}
p = next + 1;
}
return 0;
}
/* load array from INI settings */
RedisArray *ra_load_array(const char *name) {
zval *z_data, z_tmp, z_fun, z_dist;
zval z_params_hosts;
zval z_params_prev;
RedisArray *ra = NULL;
zend_string *algorithm = NULL, *user = NULL, *pass = NULL;
zend_bool b_index = 0, b_autorehash = 0, b_pconnect = 0, consistent = 0;
zend_long l_retry_interval = 0;
zend_bool b_lazy_connect = 0;
double d_connect_timeout = 0, read_timeout = 0.0;
HashTable *hHosts = NULL, *hPrev = NULL;
size_t name_len = strlen(name);
char *iptr;
/* find entry */
if(!ra_find_name(name))
return ra;
ZVAL_NULL(&z_fun);
ZVAL_NULL(&z_dist);
/* find hosts */
array_init(&z_params_hosts);
if ((iptr = INI_STR("redis.arrays.hosts")) != NULL) {
sapi_module.treat_data(PARSE_STRING, estrdup(iptr), &z_params_hosts);
if ((z_data = zend_hash_str_find(Z_ARRVAL(z_params_hosts), name, name_len)) != NULL) {
hHosts = Z_ARRVAL_P(z_data);
}
}
/* find previous hosts */
array_init(&z_params_prev);
if ((iptr = INI_STR("redis.arrays.previous")) != NULL) {
sapi_module.treat_data(PARSE_STRING, estrdup(iptr), &z_params_prev);
if ((z_data = zend_hash_str_find(Z_ARRVAL(z_params_prev), name, name_len)) != NULL) {
if (Z_TYPE_P(z_data) == IS_ARRAY) {
hPrev = Z_ARRVAL_P(z_data);
}
}
}
/* find function */
if ((iptr = INI_STR("redis.arrays.functions")) != NULL) {
array_init(&z_tmp);
sapi_module.treat_data(PARSE_STRING, estrdup(iptr), &z_tmp);
redis_conf_zval(Z_ARRVAL(z_tmp), name, name_len, &z_fun, 1, 0);
zval_dtor(&z_tmp);
}
/* find distributor */
if ((iptr = INI_STR("redis.arrays.distributor")) != NULL) {
array_init(&z_tmp);
sapi_module.treat_data(PARSE_STRING, estrdup(iptr), &z_tmp);
redis_conf_zval(Z_ARRVAL(z_tmp), name, name_len, &z_dist, 1, 0);
zval_dtor(&z_tmp);
}
/* find hash algorithm */
if ((iptr = INI_STR("redis.arrays.algorithm")) != NULL) {
array_init(&z_tmp);
sapi_module.treat_data(PARSE_STRING, estrdup(iptr), &z_tmp);
redis_conf_string(Z_ARRVAL(z_tmp), name, name_len, &algorithm);
zval_dtor(&z_tmp);
}
/* find index option */
if ((iptr = INI_STR("redis.arrays.index")) != NULL) {
array_init(&z_tmp);
sapi_module.treat_data(PARSE_STRING, estrdup(iptr), &z_tmp);
redis_conf_zend_bool(Z_ARRVAL(z_tmp), name, name_len, &b_index);
zval_dtor(&z_tmp);
}
/* find autorehash option */
if ((iptr = INI_STR("redis.arrays.autorehash")) != NULL) {
array_init(&z_tmp);
sapi_module.treat_data(PARSE_STRING, estrdup(iptr), &z_tmp);
redis_conf_zend_bool(Z_ARRVAL(z_tmp), name, name_len, &b_autorehash);
zval_dtor(&z_tmp);
}
/* find retry interval option */
if ((iptr = INI_STR("redis.arrays.retryinterval")) != NULL) {
array_init(&z_tmp);
sapi_module.treat_data(PARSE_STRING, estrdup(iptr), &z_tmp);
redis_conf_long(Z_ARRVAL(z_tmp), name, name_len, &l_retry_interval);
zval_dtor(&z_tmp);
}
/* find pconnect option */
if ((iptr = INI_STR("redis.arrays.pconnect")) != NULL) {
array_init(&z_tmp);
sapi_module.treat_data(PARSE_STRING, estrdup(iptr), &z_tmp);
redis_conf_zend_bool(Z_ARRVAL(z_tmp), name, name_len, &b_pconnect);
zval_dtor(&z_tmp);
}
/* find lazy connect option */
if ((iptr = INI_STR("redis.arrays.lazyconnect")) != NULL) {
array_init(&z_tmp);
sapi_module.treat_data(PARSE_STRING, estrdup(iptr), &z_tmp);
redis_conf_zend_bool(Z_ARRVAL(z_tmp), name, name_len, &b_lazy_connect);
zval_dtor(&z_tmp);
}
/* find connect timeout option */
if ((iptr = INI_STR("redis.arrays.connecttimeout")) != NULL) {
array_init(&z_tmp);
sapi_module.treat_data(PARSE_STRING, estrdup(iptr), &z_tmp);
redis_conf_double(Z_ARRVAL(z_tmp), name, name_len, &d_connect_timeout);
zval_dtor(&z_tmp);
}
/* find read timeout option */
if ((iptr = INI_STR("redis.arrays.readtimeout")) != NULL) {
array_init(&z_tmp);
sapi_module.treat_data(PARSE_STRING, estrdup(iptr), &z_tmp);
redis_conf_double(Z_ARRVAL(z_tmp), name, name_len, &read_timeout);
zval_dtor(&z_tmp);
}
/* find consistent option */
if ((iptr = INI_STR("redis.arrays.consistent")) != NULL) {
array_init(&z_tmp);
sapi_module.treat_data(PARSE_STRING, estrdup(iptr), &z_tmp);
if ((z_data = zend_hash_str_find(Z_ARRVAL(z_tmp), name, name_len)) != NULL) {
consistent = Z_TYPE_P(z_data) == IS_STRING && strncmp(Z_STRVAL_P(z_data), "1", 1) == 0;
}
zval_dtor(&z_tmp);
}
/* find auth option */
if ((iptr = INI_STR("redis.arrays.auth")) != NULL) {
array_init(&z_tmp);
sapi_module.treat_data(PARSE_STRING, estrdup(iptr), &z_tmp);
redis_conf_auth(Z_ARRVAL(z_tmp), name, name_len, &user, &pass);
zval_dtor(&z_tmp);
}
/* create RedisArray object */
ra = ra_make_array(hHosts, &z_fun, &z_dist, hPrev, b_index, b_pconnect, l_retry_interval,
b_lazy_connect, d_connect_timeout, read_timeout, consistent, algorithm,
user, pass);
if (ra) {
ra->auto_rehash = b_autorehash;
if(ra->prev) ra->prev->auto_rehash = b_autorehash;
}
if (algorithm) zend_string_release(algorithm);
if (user) zend_string_release(user);
if (pass) zend_string_release(pass);
zval_dtor(&z_params_hosts);
zval_dtor(&z_params_prev);
zval_dtor(&z_dist);
zval_dtor(&z_fun);
return ra;
}
static int
ra_points_cmp(const void *v1, const void *v2)
{
const ContinuumPoint *p1 = v1, *p2 = v2;
return p1->value < p2->value ? - 1 : p1->value > p2->value;
}
static Continuum *
ra_make_continuum(zend_string **hosts, int nb_hosts)
{
int i, j, k, len, idx = 0;
char host[HOST_NAME_MAX];
unsigned char digest[16];
PHP_MD5_CTX ctx;
Continuum *c;
c = ecalloc(1, sizeof(*c));
c->nb_points = nb_hosts * 160; /* 40 hashes, 4 numbers per hash = 160 points per server */
c->points = ecalloc(c->nb_points, sizeof(*c->points));
for (i = 0; i < nb_hosts; ++i) {
for (j = 0; j < 40; ++j) {
len = snprintf(host, sizeof(host), "%.*s-%u", (int)ZSTR_LEN(hosts[i]), ZSTR_VAL(hosts[i]), j);
PHP_MD5Init(&ctx);
PHP_MD5Update(&ctx, host, len);
PHP_MD5Final(digest, &ctx);
for (k = 0; k < 4; ++k) {
c->points[idx].index = i;
c->points[idx++].value = (digest[3 + k * 4] << 24)
| (digest[2 + k * 4] << 16)
| (digest[1 + k * 4] << 8)
| (digest[k * 4]);
}
}
}
qsort(c->points, c->nb_points, sizeof(*c->points), ra_points_cmp);
return c;
}
RedisArray *
ra_make_array(HashTable *hosts, zval *z_fun, zval *z_dist, HashTable *hosts_prev,
zend_bool b_index, zend_bool b_pconnect, long retry_interval,
zend_bool b_lazy_connect, double connect_timeout, double read_timeout,
zend_bool consistent, zend_string *algorithm, zend_string *user,
zend_string *pass)
{
int i, count;
RedisArray *ra;
if (!hosts || (count = zend_hash_num_elements(hosts)) == 0) return NULL;
/* create object */
ra = emalloc(sizeof(RedisArray));
ra->hosts = ecalloc(count, sizeof(*ra->hosts));
ra->redis = ecalloc(count, sizeof(*ra->redis));
ra->count = 0;
ra->z_multi_exec = NULL;
ra->index = b_index;
ra->auto_rehash = 0;
ra->pconnect = b_pconnect;
ra->connect_timeout = connect_timeout;
ra->read_timeout = read_timeout;
ra->continuum = NULL;
ra->algorithm = NULL;
if (ra_load_hosts(ra, hosts, user, pass, retry_interval, b_lazy_connect) == NULL || !ra->count) {
for (i = 0; i < ra->count; ++i) {
zval_dtor(&ra->redis[i]);
zend_string_release(ra->hosts[i]);
}
efree(ra->redis);
efree(ra->hosts);
efree(ra);
return NULL;
}
ra->prev = hosts_prev ? ra_make_array(hosts_prev, z_fun, z_dist, NULL, b_index, b_pconnect, retry_interval, b_lazy_connect, connect_timeout, read_timeout, consistent, algorithm, user, pass) : NULL;
/* init array data structures */
ra_init_function_table(ra);
/* Set hash function and distribtor if provided */
ZVAL_ZVAL(&ra->z_fun, z_fun, 1, 0);
ZVAL_ZVAL(&ra->z_dist, z_dist, 1, 0);
if (algorithm) ra->algorithm = zend_string_copy(algorithm);
/* init continuum */
if (consistent) {
ra->continuum = ra_make_continuum(ra->hosts, ra->count);
}
return ra;
}
/* call userland key extraction function */
zend_string *
ra_call_extractor(RedisArray *ra, const char *key, int key_len)
{
zend_string *out = NULL;
zval z_ret, z_argv;
/* check that we can call the extractor function */
if (!zend_is_callable_ex(&ra->z_fun, NULL, 0, NULL, NULL, NULL)) {
php_error_docref(NULL, E_ERROR, "Could not call extractor function");
return NULL;
}
ZVAL_NULL(&z_ret);
/* call extraction function */
ZVAL_STRINGL(&z_argv, key, key_len);
call_user_function(EG(function_table), NULL, &ra->z_fun, &z_ret, 1, &z_argv);
if (Z_TYPE(z_ret) == IS_STRING) {
out = zval_get_string(&z_ret);
}
zval_dtor(&z_argv);
zval_dtor(&z_ret);
return out;
}
static zend_string *
ra_extract_key(RedisArray *ra, const char *key, int key_len)
{
char *start, *end;
if (Z_TYPE(ra->z_fun) != IS_NULL) {
return ra_call_extractor(ra, key, key_len);
} else if ((start = strchr(key, '{')) == NULL || (end = strchr(start + 1, '}')) == NULL) {
return zend_string_init(key, key_len, 0);
}
/* found substring */
return zend_string_init(start + 1, end - start - 1, 0);
}
/* call userland key distributor function */
int
ra_call_distributor(RedisArray *ra, const char *key, int key_len)
{
int ret;
zval z_ret, z_argv;
/* check that we can call the extractor function */
if (!zend_is_callable_ex(&ra->z_dist, NULL, 0, NULL, NULL, NULL)) {
php_error_docref(NULL, E_ERROR, "Could not call distributor function");
return -1;
}
ZVAL_NULL(&z_ret);
/* call extraction function */
ZVAL_STRINGL(&z_argv, key, key_len);
call_user_function(EG(function_table), NULL, &ra->z_dist, &z_ret, 1, &z_argv);
ret = (Z_TYPE(z_ret) == IS_LONG) ? Z_LVAL(z_ret) : -1;
zval_dtor(&z_argv);
zval_dtor(&z_ret);
return ret;
}
zval *
ra_find_node(RedisArray *ra, const char *key, int key_len, int *out_pos)
{
int pos;
zend_string *out;
/* extract relevant part of the key */
if ((out = ra_extract_key(ra, key, key_len)) == NULL) {
return NULL;
}
if (Z_TYPE(ra->z_dist) == IS_NULL) {
int i;
unsigned long ret = 0xffffffff;
const php_hash_ops *ops;
/* hash */
if (ra->algorithm && (ops = redis_hash_fetch_ops(ra->algorithm))) {
void *ctx = emalloc(ops->context_size);
unsigned char *digest = emalloc(ops->digest_size);
#if PHP_VERSION_ID >= 80100
ops->hash_init(ctx,NULL);
#else
ops->hash_init(ctx);
#endif
ops->hash_update(ctx, (const unsigned char *)ZSTR_VAL(out), ZSTR_LEN(out));
ops->hash_final(digest, ctx);
memcpy(&ret, digest, MIN(sizeof(ret), ops->digest_size));
ret %= 0xffffffff;
efree(digest);
efree(ctx);
} else {
for (i = 0; i < ZSTR_LEN(out); ++i) {
CRC32(ret, ZSTR_VAL(out)[i]);
}
}
/* get position on ring */
if (ra->continuum) {
int left = 0, right = ra->continuum->nb_points;
while (left < right) {
i = (int)((left + right) / 2);
if (ra->continuum->points[i].value < ret) {
left = i + 1;
} else {
right = i;
}
}
if (right == ra->continuum->nb_points) {
right = 0;
}
pos = ra->continuum->points[right].index;
} else {
pos = (int)((ret ^ 0xffffffff) * ra->count / 0xffffffff);
}
} else {
pos = ra_call_distributor(ra, key, key_len);
if (pos < 0 || pos >= ra->count) {
zend_string_release(out);
return NULL;
}
}
zend_string_release(out);
if(out_pos) *out_pos = pos;
return &ra->redis[pos];
}
zval *
ra_find_node_by_name(RedisArray *ra, zend_string *host) {
int i;
for(i = 0; i < ra->count; ++i) {
if (zend_string_equals(host, ra->hosts[i])) {
return &ra->redis[i];
}
}
return NULL;
}
void
ra_index_multi(zval *z_redis, long multi_value) {
zval z_fun_multi, z_ret;
zval z_args[1];
/* run MULTI */
ZVAL_STRINGL(&z_fun_multi, "MULTI", 5);
ZVAL_LONG(&z_args[0], multi_value);
call_user_function(&redis_ce->function_table, z_redis, &z_fun_multi, &z_ret, 1, z_args);
zval_dtor(&z_fun_multi);
zval_dtor(&z_ret);
}
static void
ra_index_change_keys(const char *cmd, zval *z_keys, zval *z_redis) {
int i, argc;
zval z_fun, z_ret, *z_args;
/* alloc */
argc = 1 + zend_hash_num_elements(Z_ARRVAL_P(z_keys));
z_args = ecalloc(argc, sizeof(zval));
/* prepare first parameters */
ZVAL_STRING(&z_fun, cmd);
ZVAL_STRINGL(&z_args[0], PHPREDIS_INDEX_NAME, sizeof(PHPREDIS_INDEX_NAME) - 1);
/* prepare keys */
for(i = 0; i < argc - 1; ++i) {
zval *zv = zend_hash_index_find(Z_ARRVAL_P(z_keys), i);
if (zv == NULL) {
ZVAL_NULL(&z_args[i+1]);
} else {
z_args[i+1] = *zv;
}
}
/* run cmd */
call_user_function(&redis_ce->function_table, z_redis, &z_fun, &z_ret, argc, z_args);
zval_dtor(&z_args[0]);
zval_dtor(&z_fun);
zval_dtor(&z_ret);
efree(z_args); /* free container */
}
void
ra_index_del(zval *z_keys, zval *z_redis) {
ra_index_change_keys("SREM", z_keys, z_redis);
}
void
ra_index_keys(zval *z_pairs, zval *z_redis) {
zval z_keys, *z_val;
zend_string *zkey;
zend_ulong idx;
/* Initialize key array */
array_init_size(&z_keys, zend_hash_num_elements(Z_ARRVAL_P(z_pairs)));
/* Go through input array and add values to the key array */
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(z_pairs), idx, zkey, z_val) {
zval z_new;
PHPREDIS_NOTUSED(z_val);
if (zkey) {
ZVAL_STRINGL(&z_new, ZSTR_VAL(zkey), ZSTR_LEN(zkey));
} else {
ZVAL_LONG(&z_new, idx);
}
zend_hash_next_index_insert(Z_ARRVAL(z_keys), &z_new);
} ZEND_HASH_FOREACH_END();
/* add keys to index */
ra_index_change_keys("SADD", &z_keys, z_redis);
/* cleanup */
zval_dtor(&z_keys);
}
void
ra_index_key(const char *key, int key_len, zval *z_redis) {
zval z_fun_sadd, z_ret, z_args[2];
/* prepare args */
ZVAL_STRINGL(&z_fun_sadd, "SADD", 4);
ZVAL_STRINGL(&z_args[0], PHPREDIS_INDEX_NAME, sizeof(PHPREDIS_INDEX_NAME) - 1);
ZVAL_STRINGL(&z_args[1], key, key_len);
/* run SADD */
call_user_function(&redis_ce->function_table, z_redis, &z_fun_sadd, &z_ret, 2, z_args);
zval_dtor(&z_fun_sadd);
zval_dtor(&z_args[1]);
zval_dtor(&z_args[0]);
zval_dtor(&z_ret);
}
void
ra_index_exec(zval *z_redis, zval *return_value, int keep_all) {
zval z_fun_exec, z_ret, *zp_tmp;
/* run EXEC */
ZVAL_STRINGL(&z_fun_exec, "EXEC", 4);
call_user_function(&redis_ce->function_table, z_redis, &z_fun_exec, &z_ret, 0, NULL);
zval_dtor(&z_fun_exec);
/* extract first element of exec array and put into return_value. */
if(Z_TYPE(z_ret) == IS_ARRAY) {
if(return_value) {
if(keep_all) {
zp_tmp = &z_ret;
RETVAL_ZVAL(zp_tmp, 1, 0);
} else if ((zp_tmp = zend_hash_index_find(Z_ARRVAL(z_ret), 0)) != NULL) {
RETVAL_ZVAL(zp_tmp, 1, 0);
}
}
}
zval_dtor(&z_ret);
/* zval *zptr = &z_ret; */
/* php_var_dump(&zptr, 0); */
}
void
ra_index_discard(zval *z_redis, zval *return_value) {
zval z_fun_discard, z_ret;
/* run DISCARD */
ZVAL_STRINGL(&z_fun_discard, "DISCARD", 7);
call_user_function(&redis_ce->function_table, z_redis, &z_fun_discard, &z_ret, 0, NULL);
zval_dtor(&z_fun_discard);
zval_dtor(&z_ret);
}
void
ra_index_unwatch(zval *z_redis, zval *return_value) {
zval z_fun_unwatch, z_ret;
/* run UNWATCH */
ZVAL_STRINGL(&z_fun_unwatch, "UNWATCH", 7);
call_user_function(&redis_ce->function_table, z_redis, &z_fun_unwatch, &z_ret, 0, NULL);
zval_dtor(&z_fun_unwatch);
zval_dtor(&z_ret);
}
zend_bool
ra_is_write_cmd(RedisArray *ra, const char *cmd, int cmd_len) {
zend_bool ret;
int i;
char *cmd_up = emalloc(1 + cmd_len);
/* convert to uppercase */
for(i = 0; i < cmd_len; ++i)
cmd_up[i] = toupper(cmd[i]);
cmd_up[cmd_len] = 0;
ret = zend_hash_str_exists(ra->pure_cmds, cmd_up, cmd_len);
efree(cmd_up);
return !ret;
}
/* run TYPE to find the type */
static zend_bool
ra_get_key_type(zval *z_redis, const char *key, int key_len, zval *z_from, long *res) {
int i = 0;
zval z_fun, z_ret, z_arg, *z_data;
long success = 1;
/* Pipelined */
ra_index_multi(z_from, PIPELINE);
/* prepare args */
ZVAL_STRINGL(&z_arg, key, key_len);
/* run TYPE */
ZVAL_NULL(&z_ret);
ZVAL_STRINGL(&z_fun, "TYPE", 4);
call_user_function(&redis_ce->function_table, z_redis, &z_fun, &z_ret, 1, &z_arg);
zval_dtor(&z_fun);
zval_dtor(&z_ret);
/* run TYPE */
ZVAL_NULL(&z_ret);
ZVAL_STRINGL(&z_fun, "TTL", 3);
call_user_function(&redis_ce->function_table, z_redis, &z_fun, &z_ret, 1, &z_arg);
zval_dtor(&z_fun);
zval_dtor(&z_ret);
/* Get the result from the pipeline. */
ra_index_exec(z_from, &z_ret, 1);
if (Z_TYPE(z_ret) == IS_ARRAY) {
ZEND_HASH_FOREACH_VAL(Z_ARRVAL(z_ret), z_data) {
if (z_data == NULL || Z_TYPE_P(z_data) != IS_LONG) {
success = 0;
break;
}
/* Get the result - Might change in the future to handle doubles as well */
res[i++] = Z_LVAL_P(z_data);
} ZEND_HASH_FOREACH_END();
}
zval_dtor(&z_arg);
zval_dtor(&z_ret);
return success;
}
/* delete key from source server index during rehashing */
static void
ra_remove_from_index(zval *z_redis, const char *key, int key_len) {
zval z_fun_srem, z_ret, z_args[2];
/* run SREM on source index */
ZVAL_STRINGL(&z_fun_srem, "SREM", 4);
ZVAL_STRINGL(&z_args[0], PHPREDIS_INDEX_NAME, sizeof(PHPREDIS_INDEX_NAME) - 1);
ZVAL_STRINGL(&z_args[1], key, key_len);
call_user_function(&redis_ce->function_table, z_redis, &z_fun_srem, &z_ret, 2, z_args);
/* cleanup */
zval_dtor(&z_fun_srem);
zval_dtor(&z_args[1]);
zval_dtor(&z_args[0]);
zval_dtor(&z_ret);
}
/* delete key from source server during rehashing */
static zend_bool
ra_del_key(const char *key, int key_len, zval *z_from) {
zval z_fun_del, z_ret, z_args[1];
/* in a transaction */
ra_index_multi(z_from, MULTI);
/* run DEL on source */
ZVAL_STRINGL(&z_fun_del, "DEL", 3);
ZVAL_STRINGL(&z_args[0], key, key_len);
call_user_function(&redis_ce->function_table, z_from, &z_fun_del, &z_ret, 1, z_args);
zval_dtor(&z_fun_del);
zval_dtor(&z_args[0]);
zval_dtor(&z_ret);
/* remove key from index */
ra_remove_from_index(z_from, key, key_len);
/* close transaction */
ra_index_exec(z_from, NULL, 0);
return 1;
}
static zend_bool
ra_expire_key(const char *key, int key_len, zval *z_to, long ttl) {
zval z_fun_expire, z_ret, z_args[2];
if (ttl > 0)
{
/* run EXPIRE on target */
ZVAL_STRINGL(&z_fun_expire, "EXPIRE", 6);
ZVAL_STRINGL(&z_args[0], key, key_len);
ZVAL_LONG(&z_args[1], ttl);
call_user_function(&redis_ce->function_table, z_to, &z_fun_expire, &z_ret, 2, z_args);
zval_dtor(&z_fun_expire);
zval_dtor(&z_args[0]);
zval_dtor(&z_ret);
}
return 1;
}
static zend_bool
ra_move_zset(const char *key, int key_len, zval *z_from, zval *z_to, long ttl) {
zval z_fun_zrange, z_fun_zadd, z_ret, z_ret_dest, z_args[4], *z_zadd_args, *z_score_p;
int i, count;
HashTable *h_zset_vals;
zend_string *zkey;
zend_ulong idx;
/* run ZRANGE key 0 -1 WITHSCORES on source */
ZVAL_STRINGL(&z_fun_zrange, "ZRANGE", 6);
ZVAL_STRINGL(&z_args[0], key, key_len);
ZVAL_STRINGL(&z_args[1], "0", 1);
ZVAL_STRINGL(&z_args[2], "-1", 2);
ZVAL_BOOL(&z_args[3], 1);
call_user_function(&redis_ce->function_table, z_from, &z_fun_zrange, &z_ret, 4, z_args);
zval_dtor(&z_fun_zrange);
zval_dtor(&z_args[2]);
zval_dtor(&z_args[1]);
zval_dtor(&z_args[0]);
if(Z_TYPE(z_ret) != IS_ARRAY) { /* key not found or replaced */
/* TODO: report? */
zval_dtor(&z_ret);
return 0;
}
/* we now have an array of value → score pairs in z_ret. */
h_zset_vals = Z_ARRVAL(z_ret);
/* allocate argument array for ZADD */
count = zend_hash_num_elements(h_zset_vals);
z_zadd_args = ecalloc((1 + 2*count), sizeof(zval));
ZVAL_STRINGL(&z_zadd_args[0], key, key_len);
i = 1;
ZEND_HASH_FOREACH_KEY_VAL(h_zset_vals, idx, zkey, z_score_p) {
/* add score */
ZVAL_DOUBLE(&z_zadd_args[i], Z_DVAL_P(z_score_p));
/* add value */
if (zkey) {
ZVAL_STRINGL(&z_zadd_args[i+1], ZSTR_VAL(zkey), ZSTR_LEN(zkey));
} else {
ZVAL_LONG(&z_zadd_args[i+1], (long)idx);
}
i += 2;
} ZEND_HASH_FOREACH_END();
/* run ZADD on target */
ZVAL_STRINGL(&z_fun_zadd, "ZADD", 4);
call_user_function(&redis_ce->function_table, z_to, &z_fun_zadd, &z_ret_dest, 1 + 2 * count, z_zadd_args);
/* Expire if needed */
ra_expire_key(key, key_len, z_to, ttl);
/* cleanup */
zval_dtor(&z_fun_zadd);
zval_dtor(&z_ret_dest);
zval_dtor(&z_ret);
/* Free the array itself */
for (i = 0; i < 1 + 2 * count; i++) {
zval_dtor(&z_zadd_args[i]);
}
efree(z_zadd_args);
return 1;
}
static zend_bool
ra_move_string(const char *key, int key_len, zval *z_from, zval *z_to, long ttl) {
zval z_fun_get, z_fun_set, z_ret, z_args[3];
/* run GET on source */
ZVAL_STRINGL(&z_fun_get, "GET", 3);
ZVAL_STRINGL(&z_args[0], key, key_len);
call_user_function(&redis_ce->function_table, z_from, &z_fun_get, &z_ret, 1, z_args);
zval_dtor(&z_fun_get);
if(Z_TYPE(z_ret) != IS_STRING) { /* key not found or replaced */
/* TODO: report? */
zval_dtor(&z_args[0]);
zval_dtor(&z_ret);
return 0;
}
/* run SET on target */
if (ttl > 0) {
ZVAL_STRINGL(&z_fun_set, "SETEX", 5);
ZVAL_LONG(&z_args[1], ttl);
ZVAL_STRINGL(&z_args[2], Z_STRVAL(z_ret), Z_STRLEN(z_ret)); /* copy z_ret to arg 1 */
zval_dtor(&z_ret); /* free memory from our previous call */
call_user_function(&redis_ce->function_table, z_to, &z_fun_set, &z_ret, 3, z_args);
/* cleanup */
zval_dtor(&z_args[2]);
} else {
ZVAL_STRINGL(&z_fun_set, "SET", 3);
ZVAL_STRINGL(&z_args[1], Z_STRVAL(z_ret), Z_STRLEN(z_ret)); /* copy z_ret to arg 1 */
zval_dtor(&z_ret); /* free memory from our previous return value */
call_user_function(&redis_ce->function_table, z_to, &z_fun_set, &z_ret, 2, z_args);
/* cleanup */
zval_dtor(&z_args[1]);
}
zval_dtor(&z_fun_set);
zval_dtor(&z_args[0]);
zval_dtor(&z_ret);
return 1;
}
static zend_bool
ra_move_hash(const char *key, int key_len, zval *z_from, zval *z_to, long ttl) {
zval z_fun_hgetall, z_fun_hmset, z_ret_dest, z_args[2];
/* run HGETALL on source */
ZVAL_STRINGL(&z_args[0], key, key_len);
ZVAL_STRINGL(&z_fun_hgetall, "HGETALL", 7);
call_user_function(&redis_ce->function_table, z_from, &z_fun_hgetall, &z_args[1], 1, z_args);
zval_dtor(&z_fun_hgetall);
if (Z_TYPE(z_args[1]) != IS_ARRAY) { /* key not found or replaced */
/* TODO: report? */
zval_dtor(&z_args[1]);
zval_dtor(&z_args[0]);
return 0;
}
/* run HMSET on target */
ZVAL_STRINGL(&z_fun_hmset, "HMSET", 5);
call_user_function(&redis_ce->function_table, z_to, &z_fun_hmset, &z_ret_dest, 2, z_args);
zval_dtor(&z_fun_hmset);
zval_dtor(&z_ret_dest);
/* Expire if needed */
ra_expire_key(key, key_len, z_to, ttl);
/* cleanup */
zval_dtor(&z_args[1]);
zval_dtor(&z_args[0]);
return 1;
}
static zend_bool
ra_move_collection(const char *key, int key_len, zval *z_from, zval *z_to,
int list_count, const char **cmd_list,
int add_count, const char **cmd_add, long ttl) {
zval z_fun_retrieve, z_fun_sadd, z_ret, *z_retrieve_args, *z_sadd_args, *z_data_p;
int count, i;
HashTable *h_set_vals;
/* run retrieval command on source */
ZVAL_STRING(&z_fun_retrieve, cmd_list[0]); /* set the command */
z_retrieve_args = ecalloc(list_count, sizeof(zval));
/* set the key */
ZVAL_STRINGL(&z_retrieve_args[0], key, key_len);
/* possibly add some other args if they were provided. */
for(i = 1; i < list_count; ++i) {
ZVAL_STRING(&z_retrieve_args[i], cmd_list[i]);
}
call_user_function(&redis_ce->function_table, z_from, &z_fun_retrieve, &z_ret, list_count, z_retrieve_args);
/* cleanup */
zval_dtor(&z_fun_retrieve);
for(i = 0; i < list_count; ++i) {
zval_dtor(&z_retrieve_args[i]);
}
efree(z_retrieve_args);
if(Z_TYPE(z_ret) != IS_ARRAY) { /* key not found or replaced */
/* TODO: report? */
zval_dtor(&z_ret);
return 0;
}
/* run SADD/RPUSH on target */
h_set_vals = Z_ARRVAL(z_ret);
count = 1 + zend_hash_num_elements(h_set_vals);
ZVAL_STRING(&z_fun_sadd, cmd_add[0]);
z_sadd_args = ecalloc(count, sizeof(zval));
ZVAL_STRINGL(&z_sadd_args[0], key, key_len);
i = 1;
ZEND_HASH_FOREACH_VAL(h_set_vals, z_data_p) {
/* add set elements */
ZVAL_ZVAL(&z_sadd_args[i], z_data_p, 1, 0);
i++;
} ZEND_HASH_FOREACH_END();
/* Clean up our input return value */
zval_dtor(&z_ret);
call_user_function(&redis_ce->function_table, z_to, &z_fun_sadd, &z_ret, count, z_sadd_args);
/* cleanup */
zval_dtor(&z_fun_sadd);
for (i = 0; i < count; i++) {
zval_dtor(&z_sadd_args[i]);
}
efree(z_sadd_args);
/* Clean up our output return value */
zval_dtor(&z_ret);
/* Expire if needed */
ra_expire_key(key, key_len, z_to, ttl);
return 1;
}
static zend_bool
ra_move_set(const char *key, int key_len, zval *z_from, zval *z_to, long ttl) {
const char *cmd_list[] = {"SMEMBERS"};
const char *cmd_add[] = {"SADD"};
return ra_move_collection(key, key_len, z_from, z_to, 1, cmd_list, 1, cmd_add, ttl);
}
static zend_bool
ra_move_list(const char *key, int key_len, zval *z_from, zval *z_to, long ttl) {
const char *cmd_list[] = {"LRANGE", "0", "-1"};
const char *cmd_add[] = {"RPUSH"};
return ra_move_collection(key, key_len, z_from, z_to, 3, cmd_list, 1, cmd_add, ttl);
}
void
ra_move_key(const char *key, int key_len, zval *z_from, zval *z_to) {
long res[2] = {0}, type, ttl;
zend_bool success = 0;
if (ra_get_key_type(z_from, key, key_len, z_from, res)) {
type = res[0];
ttl = res[1];
/* open transaction on target server */
ra_index_multi(z_to, MULTI);
switch(type) {
case REDIS_STRING:
success = ra_move_string(key, key_len, z_from, z_to, ttl);
break;
case REDIS_SET:
success = ra_move_set(key, key_len, z_from, z_to, ttl);
break;
case REDIS_LIST:
success = ra_move_list(key, key_len, z_from, z_to, ttl);
break;
case REDIS_ZSET:
success = ra_move_zset(key, key_len, z_from, z_to, ttl);
break;
case REDIS_HASH:
success = ra_move_hash(key, key_len, z_from, z_to, ttl);
break;
default:
/* TODO: report? */
break;
}
}
if(success) {
ra_del_key(key, key_len, z_from);
ra_index_key(key, key_len, z_to);
}
/* close transaction */
ra_index_exec(z_to, NULL, 0);
}
/* callback with the current progress, with hostname and count */
static void
zval_rehash_callback(zend_fcall_info *z_cb, zend_fcall_info_cache *z_cb_cache,
zend_string *hostname, long count) {
zval zv, *z_ret = &zv;
ZVAL_NULL(z_ret);
zval z_args[2];
ZVAL_STRINGL(&z_args[0], ZSTR_VAL(hostname), ZSTR_LEN(hostname));
ZVAL_LONG(&z_args[1], count);
z_cb->params = z_args;
z_cb->retval = z_ret;
z_cb->param_count = 2;
/* run cb(hostname, count) */
zend_call_function(z_cb, z_cb_cache);
/* cleanup */
zval_dtor(&z_args[0]);
zval_dtor(z_ret);
}
static void
ra_rehash_server(RedisArray *ra, zval *z_redis, zend_string *hostname, zend_bool b_index,
zend_fcall_info *z_cb, zend_fcall_info_cache *z_cb_cache) {
HashTable *h_keys;
long count = 0;
zval z_fun, z_ret, z_argv, *z_ele;
/* list all keys */
if (b_index) {
ZVAL_STRING(&z_fun, "SMEMBERS");
ZVAL_STRING(&z_argv, PHPREDIS_INDEX_NAME);
} else {
ZVAL_STRING(&z_fun, "KEYS");
ZVAL_STRING(&z_argv, "*");
}
ZVAL_NULL(&z_ret);
call_user_function(&redis_ce->function_table, z_redis, &z_fun, &z_ret, 1, &z_argv);
zval_dtor(&z_argv);
zval_dtor(&z_fun);
if (Z_TYPE(z_ret) == IS_ARRAY) {
h_keys = Z_ARRVAL(z_ret);
count = zend_hash_num_elements(h_keys);
}
if (!count) {
zval_dtor(&z_ret);
return;
}
/* callback */
if(z_cb && z_cb_cache) {
zval_rehash_callback(z_cb, z_cb_cache, hostname, count);
}
/* for each key, redistribute */
ZEND_HASH_FOREACH_VAL(h_keys, z_ele) {
int pos = 0;
/* check that we're not moving to the same node. */
zval *z_target = ra_find_node(ra, Z_STRVAL_P(z_ele), Z_STRLEN_P(z_ele), &pos);
if (z_target && !zend_string_equals(hostname, ra->hosts[pos])) { /* different host */
ra_move_key(Z_STRVAL_P(z_ele), Z_STRLEN_P(z_ele), z_redis, z_target);
}
} ZEND_HASH_FOREACH_END();
/* cleanup */
zval_dtor(&z_ret);
}
void
ra_rehash(RedisArray *ra, zend_fcall_info *z_cb, zend_fcall_info_cache *z_cb_cache) {
int i;
/* redistribute the data, server by server. */
if(!ra->prev)
return; /* TODO: compare the two rings for equality */
for(i = 0; i < ra->prev->count; ++i) {
ra_rehash_server(ra, &ra->prev->redis[i], ra->prev->hosts[i], ra->index, z_cb, z_cb_cache);
}
}
redis-6.0.2/redis_array_impl.h 0000644 0001750 0000012 00000003005 14515245367 017114 0 ustar pyatsukhnenko wheel #ifndef REDIS_ARRAY_IMPL_H
#define REDIS_ARRAY_IMPL_H
#if (defined(_MSC_VER) && _MSC_VER <= 1920)
#include
#else
#include
#endif
#include "redis_array.h"
RedisArray *ra_load_array(const char *name);
RedisArray *ra_make_array(HashTable *hosts, zval *z_fun, zval *z_dist,
HashTable *hosts_prev, zend_bool b_index,
zend_bool b_pconnect, long retry_interval,
zend_bool b_lazy_connect, double connect_timeout,
double read_timeout, zend_bool consistent,
zend_string *algorithm, zend_string *auth,
zend_string *pass);
zval *ra_find_node_by_name(RedisArray *ra, zend_string *host);
zval *ra_find_node(RedisArray *ra, const char *key, int key_len, int *out_pos);
void ra_init_function_table(RedisArray *ra);
void ra_move_key(const char *key, int key_len, zval *z_from, zval *z_to);
void ra_index_multi(zval *z_redis, long multi_value);
void ra_index_key(const char *key, int key_len, zval *z_redis);
void ra_index_keys(zval *z_pairs, zval *z_redis);
void ra_index_del(zval *z_keys, zval *z_redis);
void ra_index_exec(zval *z_redis, zval *return_value, int keep_all);
void ra_index_discard(zval *z_redis, zval *return_value);
void ra_index_unwatch(zval *z_redis, zval *return_value);
zend_bool ra_is_write_cmd(RedisArray *ra, const char *cmd, int cmd_len);
void ra_rehash(RedisArray *ra, zend_fcall_info *z_cb, zend_fcall_info_cache *z_cb_cache);
#endif
redis-6.0.2/redis_cluster.c 0000644 0001750 0000012 00000273630 14515245367 016446 0 ustar pyatsukhnenko wheel /*
+----------------------------------------------------------------------+
| Copyright (c) 1997-2009 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Michael Grunder |
| Maintainer: Nicolas Favre-Felix |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "common.h"
#include "php_redis.h"
#include "ext/standard/info.h"
#include "crc16.h"
#include "redis_cluster.h"
#include "redis_commands.h"
#include
#include
#include "library.h"
#include
#include
zend_class_entry *redis_cluster_ce;
/* Exception handler */
zend_class_entry *redis_cluster_exception_ce;
#if PHP_VERSION_ID < 80000
#include "redis_cluster_legacy_arginfo.h"
#else
#include "zend_attributes.h"
#include "redis_cluster_arginfo.h"
#endif
PHP_MINIT_FUNCTION(redis_cluster)
{
redis_cluster_ce = register_class_RedisCluster();
redis_cluster_ce->create_object = create_cluster_context;
redis_cluster_exception_ce = register_class_RedisClusterException(spl_ce_RuntimeException);
return SUCCESS;
}
/* Handlers for RedisCluster */
zend_object_handlers RedisCluster_handlers;
/* Our context seeds will be a hash table with RedisSock* pointers */
static void ht_free_seed(zval *data) {
RedisSock *redis_sock = *(RedisSock**)data;
if (redis_sock) redis_free_socket(redis_sock);
}
/* Free redisClusterNode objects we've stored */
static void ht_free_node(zval *data) {
redisClusterNode *node = *(redisClusterNode**)data;
cluster_free_node(node);
}
/* Create redisCluster context */
zend_object * create_cluster_context(zend_class_entry *class_type) {
redisCluster *cluster;
// Allocate our actual struct
cluster = ecalloc(1, sizeof(redisCluster) + zend_object_properties_size(class_type));
// We're not currently subscribed anywhere
cluster->subscribed_slot = -1;
// Allocate our RedisSock we'll use to store prefix/serialization flags
cluster->flags = ecalloc(1, sizeof(RedisSock));
// Allocate our hash table for seeds
ALLOC_HASHTABLE(cluster->seeds);
zend_hash_init(cluster->seeds, 0, NULL, ht_free_seed, 0);
// Allocate our hash table for connected Redis objects
ALLOC_HASHTABLE(cluster->nodes);
zend_hash_init(cluster->nodes, 0, NULL, ht_free_node, 0);
// Initialize it
zend_object_std_init(&cluster->std, class_type);
object_properties_init(&cluster->std, class_type);
memcpy(&RedisCluster_handlers, zend_get_std_object_handlers(), sizeof(RedisCluster_handlers));
RedisCluster_handlers.offset = XtOffsetOf(redisCluster, std);
RedisCluster_handlers.free_obj = free_cluster_context;
cluster->std.handlers = &RedisCluster_handlers;
return &cluster->std;
}
/* Free redisCluster context */
void free_cluster_context(zend_object *object) {
redisCluster *cluster = PHPREDIS_GET_OBJECT(redisCluster, object);
cluster_free(cluster, 0);
zend_object_std_dtor(&cluster->std);
}
/* Take user provided seeds and return unique and valid ones */
/* Attempt to connect to a Redis cluster provided seeds and timeout options */
static void redis_cluster_init(redisCluster *c, HashTable *ht_seeds, double timeout,
double read_timeout, int persistent, zend_string *user,
zend_string *pass, zval *context)
{
zend_string *hash = NULL, **seeds;
redisCachedCluster *cc;
uint32_t nseeds;
char *err;
/* Validate our arguments and get a sanitized seed array */
seeds = cluster_validate_args(timeout, read_timeout, ht_seeds, &nseeds, &err);
if (seeds == NULL) {
CLUSTER_THROW_EXCEPTION(err, 0);
return;
}
if (user && ZSTR_LEN(user))
c->flags->user = zend_string_copy(user);
if (pass && ZSTR_LEN(pass))
c->flags->pass = zend_string_copy(pass);
if (context) {
redis_sock_set_stream_context(c->flags, context);
}
c->flags->timeout = timeout;
c->flags->read_timeout = read_timeout;
c->flags->persistent = persistent;
c->waitms = timeout * 1000L;
/* Attempt to load slots from cache if caching is enabled */
if (CLUSTER_CACHING_ENABLED()) {
/* Exit early if we can load from cache */
hash = cluster_hash_seeds(seeds, nseeds);
if ((cc = cluster_cache_load(hash))) {
cluster_init_cache(c, cc);
goto cleanup;
}
}
/* Initialize seeds and attempt to map keyspace */
cluster_init_seeds(c, seeds, nseeds);
if (cluster_map_keyspace(c) == SUCCESS && hash)
cluster_cache_store(hash, c->nodes);
cleanup:
if (hash) zend_string_release(hash);
free_seed_array(seeds, nseeds);
}
/* Attempt to load a named cluster configured in php.ini */
void redis_cluster_load(redisCluster *c, char *name, int name_len) {
zval z_seeds, z_tmp, *z_value;
zend_string *user = NULL, *pass = NULL;
double timeout = 0, read_timeout = 0;
int persistent = 0;
char *iptr;
HashTable *ht_seeds = NULL;
/* Seeds */
array_init(&z_seeds);
if ((iptr = INI_STR("redis.clusters.seeds")) != NULL) {
sapi_module.treat_data(PARSE_STRING, estrdup(iptr), &z_seeds);
}
if ((z_value = zend_hash_str_find(Z_ARRVAL(z_seeds), name, name_len)) != NULL) {
ht_seeds = Z_ARRVAL_P(z_value);
} else {
zval_dtor(&z_seeds);
CLUSTER_THROW_EXCEPTION("Couldn't find seeds for cluster", 0);
return;
}
/* Connection timeout */
if ((iptr = INI_STR("redis.clusters.timeout")) != NULL) {
array_init(&z_tmp);
sapi_module.treat_data(PARSE_STRING, estrdup(iptr), &z_tmp);
redis_conf_double(Z_ARRVAL(z_tmp), name, name_len, &timeout);
zval_dtor(&z_tmp);
}
/* Read timeout */
if ((iptr = INI_STR("redis.clusters.read_timeout")) != NULL) {
array_init(&z_tmp);
sapi_module.treat_data(PARSE_STRING, estrdup(iptr), &z_tmp);
redis_conf_double(Z_ARRVAL(z_tmp), name, name_len, &read_timeout);
zval_dtor(&z_tmp);
}
/* Persistent connections */
if ((iptr = INI_STR("redis.clusters.persistent")) != NULL) {
array_init(&z_tmp);
sapi_module.treat_data(PARSE_STRING, estrdup(iptr), &z_tmp);
redis_conf_bool(Z_ARRVAL(z_tmp), name, name_len, &persistent);
zval_dtor(&z_tmp);
}
if ((iptr = INI_STR("redis.clusters.auth"))) {
array_init(&z_tmp);
sapi_module.treat_data(PARSE_STRING, estrdup(iptr), &z_tmp);
redis_conf_auth(Z_ARRVAL(z_tmp), name, name_len, &user, &pass);
zval_dtor(&z_tmp);
}
/* Attempt to create/connect to the cluster */
redis_cluster_init(c, ht_seeds, timeout, read_timeout, persistent, user, pass, NULL);
/* Clean up */
zval_dtor(&z_seeds);
if (user) zend_string_release(user);
if (pass) zend_string_release(pass);
}
/*
* PHP Methods
*/
/* Create a RedisCluster Object */
PHP_METHOD(RedisCluster, __construct) {
zval *object, *z_seeds = NULL, *z_auth = NULL, *context = NULL;
zend_string *user = NULL, *pass = NULL;
double timeout = 0.0, read_timeout = 0.0;
size_t name_len;
zend_bool persistent = 0;
redisCluster *c = GET_CONTEXT();
char *name;
// Parse arguments
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(),
"Os!|addbza!", &object, redis_cluster_ce, &name,
&name_len, &z_seeds, &timeout, &read_timeout,
&persistent, &z_auth, &context) == FAILURE)
{
RETURN_FALSE;
}
/* If we've got a string try to load from INI */
if (ZEND_NUM_ARGS() < 2) {
if (name_len == 0) { // Require a name
CLUSTER_THROW_EXCEPTION("You must specify a name or pass seeds!", 0);
}
redis_cluster_load(c, name, name_len);
return;
}
/* The normal case, loading from arguments */
redis_extract_auth_info(z_auth, &user, &pass);
redis_cluster_init(c, Z_ARRVAL_P(z_seeds), timeout, read_timeout,
persistent, user, pass, context);
if (user) zend_string_release(user);
if (pass) zend_string_release(pass);
}
/*
* RedisCluster method implementation
*/
/* {{{ proto bool RedisCluster::close() */
PHP_METHOD(RedisCluster, close) {
cluster_disconnect(GET_CONTEXT(), 1);
RETURN_TRUE;
}
/* {{{ proto string RedisCluster::get(string key) */
PHP_METHOD(RedisCluster, get) {
CLUSTER_PROCESS_KW_CMD("GET", redis_key_cmd, cluster_bulk_resp, 1);
}
/* }}} */
/* {{{ proto bool RedisCluster::set(string key, string value) */
PHP_METHOD(RedisCluster, set) {
CLUSTER_PROCESS_CMD(set, cluster_set_resp, 0);
}
/* }}} */
/* Generic handler for MGET/MSET/MSETNX */
static int
distcmd_resp_handler(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, short slot,
clusterMultiCmd *mc, zval *z_ret, int last, cluster_cb cb)
{
clusterMultiCtx *ctx;
// Finalize multi command
cluster_multi_fini(mc);
// Spin up multi context
ctx = emalloc(sizeof(clusterMultiCtx));
ctx->z_multi = z_ret;
ctx->count = mc->argc;
ctx->last = last;
// Attempt to send the command
if (cluster_send_command(c,slot,mc->cmd.c,mc->cmd.len) < 0 || c->err != NULL) {
efree(ctx);
return -1;
}
if (CLUSTER_IS_ATOMIC(c)) {
// Process response now
cb(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, (void*)ctx);
} else {
CLUSTER_ENQUEUE_RESPONSE(c, slot, cb, ctx);
}
// Clear out our command but retain allocated memory
CLUSTER_MULTI_CLEAR(mc);
return 0;
}
/* Container struct for a key/value pair pulled from an array */
typedef struct clusterKeyValHT {
char kbuf[22];
char *key;
size_t key_len;
int key_free;
short slot;
char *val;
size_t val_len;
int val_free;
} clusterKeyValHT;
/* Helper to pull a key/value pair from a HashTable */
static int get_key_val_ht(redisCluster *c, HashTable *ht, HashPosition *ptr,
clusterKeyValHT *kv)
{
zval *z_val;
zend_ulong idx;
// Grab the key, convert it to a string using provided kbuf buffer if it's
// a LONG style key
zend_string *zkey;
switch (zend_hash_get_current_key_ex(ht, &zkey, &idx, ptr)) {
case HASH_KEY_IS_STRING:
kv->key_len = ZSTR_LEN(zkey);
kv->key = ZSTR_VAL(zkey);
break;
case HASH_KEY_IS_LONG:
kv->key_len = snprintf(kv->kbuf,sizeof(kv->kbuf),"%ld",(long)idx);
kv->key = kv->kbuf;
break;
default:
CLUSTER_THROW_EXCEPTION("Internal Zend HashTable error", 0);
return -1;
}
// Prefix our key if we need to, set the slot
kv->key_free = redis_key_prefix(c->flags, &(kv->key), &(kv->key_len));
kv->slot = cluster_hash_key(kv->key, kv->key_len);
// Now grab our value
if ((z_val = zend_hash_get_current_data_ex(ht, ptr)) == NULL) {
CLUSTER_THROW_EXCEPTION("Internal Zend HashTable error", 0);
return -1;
}
// Serialize our value if required
kv->val_free = redis_pack(c->flags,z_val,&(kv->val),&(kv->val_len));
// Success
return 0;
}
/* Helper to pull, prefix, and hash a key from a HashTable value */
static int get_key_ht(redisCluster *c, HashTable *ht, HashPosition *ptr,
clusterKeyValHT *kv)
{
zval *z_key;
if ((z_key = zend_hash_get_current_data_ex(ht, ptr)) == NULL) {
// Shouldn't happen, but check anyway
CLUSTER_THROW_EXCEPTION("Internal Zend HashTable error", 0);
return -1;
}
// Always want to work with strings
convert_to_string(z_key);
kv->key = Z_STRVAL_P(z_key);
kv->key_len = Z_STRLEN_P(z_key);
kv->key_free = redis_key_prefix(c->flags, &(kv->key), &(kv->key_len));
// Hash our key
kv->slot = cluster_hash_key(kv->key, kv->key_len);
// Success
return 0;
}
/* Turn variable arguments into a HashTable for processing */
static HashTable *method_args_to_ht(zval *z_args, int argc) {
HashTable *ht_ret;
int i;
/* Allocate our hash table */
ALLOC_HASHTABLE(ht_ret);
zend_hash_init(ht_ret, argc, NULL, NULL, 0);
/* Populate our return hash table with our arguments */
for (i = 0; i < argc; i++) {
zend_hash_next_index_insert(ht_ret, &z_args[i]);
}
/* Return our hash table */
return ht_ret;
}
/* Convenience handler for commands that take multiple keys such as
* MGET, DEL, and UNLINK */
static int cluster_mkey_cmd(INTERNAL_FUNCTION_PARAMETERS, char *kw, int kw_len,
zval *z_ret, cluster_cb cb)
{
redisCluster *c = GET_CONTEXT();
clusterMultiCmd mc = {0};
clusterKeyValHT kv;
zval *z_args;
HashTable *ht_arr;
HashPosition ptr;
int i = 1, argc = ZEND_NUM_ARGS(), ht_free = 0;
short slot;
/* If we don't have any arguments we're invalid */
if (!argc) return -1;
/* Extract our arguments into an array */
z_args = ecalloc(argc, sizeof(zval));
if (zend_get_parameters_array(ht, argc, z_args) == FAILURE) {
efree(z_args);
return -1;
}
/* Determine if we're working with a single array or variadic args */
if (argc == 1 && Z_TYPE(z_args[0]) == IS_ARRAY) {
ht_arr = Z_ARRVAL(z_args[0]);
argc = zend_hash_num_elements(ht_arr);
if (!argc) {
efree(z_args);
return -1;
}
} else {
ht_arr = method_args_to_ht(z_args, argc);
ht_free = 1;
}
/* MGET is readonly, DEL is not */
c->readonly = kw_len == 4 && CLUSTER_IS_ATOMIC(c);
// Initialize our "multi" command handler with command/len
CLUSTER_MULTI_INIT(mc, kw, kw_len);
// Process the first key outside of our loop, so we don't have to check if
// it's the first iteration every time, needlessly
zend_hash_internal_pointer_reset_ex(ht_arr, &ptr);
if (get_key_ht(c, ht_arr, &ptr, &kv) < 0) {
efree(z_args);
return -1;
}
// Process our key and add it to the command
cluster_multi_add(&mc, kv.key, kv.key_len);
// Free key if we prefixed
if (kv.key_free) efree(kv.key);
// Move to the next key
zend_hash_move_forward_ex(ht_arr, &ptr);
// Iterate over keys 2...N
slot = kv.slot;
while (zend_hash_has_more_elements_ex(ht_arr, &ptr) ==SUCCESS) {
if (get_key_ht(c, ht_arr, &ptr, &kv) < 0) {
cluster_multi_free(&mc);
if (ht_free) {
zend_hash_destroy(ht_arr);
efree(ht_arr);
}
efree(z_args);
return -1;
}
// If the slots have changed, kick off the keys we've aggregated
if (slot != kv.slot) {
// Process this batch of MGET keys
if (distcmd_resp_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, slot,
&mc, z_ret, i == argc, cb) < 0)
{
cluster_multi_free(&mc);
if (ht_free) {
zend_hash_destroy(ht_arr);
efree(ht_arr);
}
efree(z_args);
return -1;
}
}
// Add this key to the command
cluster_multi_add(&mc, kv.key, kv.key_len);
// Free key if we prefixed
if (kv.key_free) efree(kv.key);
// Update the last slot we encountered, and the key we're on
slot = kv.slot;
i++;
zend_hash_move_forward_ex(ht_arr, &ptr);
}
efree(z_args);
// If we've got straggler(s) process them
if (mc.argc > 0) {
if (distcmd_resp_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, slot,
&mc, z_ret, 1, cb) < 0)
{
cluster_multi_free(&mc);
if (ht_free) {
zend_hash_destroy(ht_arr);
efree(ht_arr);
}
return -1;
}
}
// Free our command
cluster_multi_free(&mc);
/* Clean up our hash table if we constructed it from variadic args */
if (ht_free) {
zend_hash_destroy(ht_arr);
efree(ht_arr);
}
/* Return our object if we're in MULTI mode */
if (!CLUSTER_IS_ATOMIC(c))
RETVAL_ZVAL(getThis(), 1, 0);
// Success
return 0;
}
/* Handler for both MSET and MSETNX */
static int cluster_mset_cmd(INTERNAL_FUNCTION_PARAMETERS, char *kw, int kw_len,
zval *z_ret, cluster_cb cb)
{
redisCluster *c = GET_CONTEXT();
clusterKeyValHT kv;
clusterMultiCmd mc = {0};
zval *z_arr;
HashTable *ht_arr;
HashPosition ptr;
int i = 1, argc;
short slot;
// Parse our arguments
if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &z_arr) == FAILURE) {
return -1;
}
// No reason to send zero args
ht_arr = Z_ARRVAL_P(z_arr);
if ((argc = zend_hash_num_elements(ht_arr)) == 0) {
return -1;
}
/* This is a write command */
c->readonly = 0;
// Set up our multi command handler
CLUSTER_MULTI_INIT(mc, kw, kw_len);
// Process the first key/value pair outside of our loop
zend_hash_internal_pointer_reset_ex(ht_arr, &ptr);
if (get_key_val_ht(c, ht_arr, &ptr, &kv) ==-1) return -1;
zend_hash_move_forward_ex(ht_arr, &ptr);
// Add this to our multi cmd, set slot, free key if we prefixed
cluster_multi_add(&mc, kv.key, kv.key_len);
cluster_multi_add(&mc, kv.val, kv.val_len);
if (kv.key_free) efree(kv.key);
if (kv.val_free) efree(kv.val);
// While we've got more keys to set
slot = kv.slot;
while (zend_hash_has_more_elements_ex(ht_arr, &ptr) ==SUCCESS) {
// Pull the next key/value pair
if (get_key_val_ht(c, ht_arr, &ptr, &kv) ==-1) {
return -1;
}
// If the slots have changed, process responses
if (slot != kv.slot) {
if (distcmd_resp_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, c,
slot, &mc, z_ret, i == argc, cb) < 0)
{
cluster_multi_free(&mc);
return -1;
}
}
// Add this key and value to our command
cluster_multi_add(&mc, kv.key, kv.key_len);
cluster_multi_add(&mc, kv.val, kv.val_len);
// Free our key and value if we need to
if (kv.key_free) efree(kv.key);
if (kv.val_free) efree(kv.val);
// Update our slot, increment position
slot = kv.slot;
i++;
// Move on
zend_hash_move_forward_ex(ht_arr, &ptr);
}
// If we've got stragglers, process them too
if (mc.argc > 0) {
if (distcmd_resp_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, slot, &mc,
z_ret, 1, cb) < 0)
{
cluster_multi_free(&mc);
return -1;
}
}
// Free our command
cluster_multi_free(&mc);
/* Return our object if we're in MULTI mode */
if (!CLUSTER_IS_ATOMIC(c))
RETVAL_ZVAL(getThis(), 1, 0);
// Success
return 0;
}
/* Generic passthru for DEL and UNLINK which act identically */
static void cluster_generic_delete(INTERNAL_FUNCTION_PARAMETERS,
char *kw, int kw_len)
{
zval *z_ret = emalloc(sizeof(*z_ret));
// Initialize a LONG value to zero for our return
ZVAL_LONG(z_ret, 0);
// Parse args, process
if (cluster_mkey_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, kw, kw_len, z_ret,
cluster_del_resp) < 0)
{
efree(z_ret);
RETURN_FALSE;
}
}
/* {{{ proto array RedisCluster::del(string key1, string key2, ... keyN) */
PHP_METHOD(RedisCluster, del) {
cluster_generic_delete(INTERNAL_FUNCTION_PARAM_PASSTHRU, "DEL", sizeof("DEL") - 1);
}
/* {{{ proto array RedisCluster::unlink(string key1, string key2, ... keyN) */
PHP_METHOD(RedisCluster, unlink) {
cluster_generic_delete(INTERNAL_FUNCTION_PARAM_PASSTHRU, "UNLINK", sizeof("UNLINK") - 1);
}
/* {{{ proto array RedisCluster::mget(array keys) */
PHP_METHOD(RedisCluster, mget) {
zval *z_ret = emalloc(sizeof(*z_ret));
array_init(z_ret);
// Parse args, process
if (cluster_mkey_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "MGET",
sizeof("MGET")-1, z_ret, cluster_mbulk_mget_resp) < 0)
{
zval_dtor(z_ret);
efree(z_ret);
RETURN_FALSE;
}
}
/* {{{ proto bool RedisCluster::mset(array keyvalues) */
PHP_METHOD(RedisCluster, mset) {
zval *z_ret = emalloc(sizeof(*z_ret));
ZVAL_TRUE(z_ret);
// Parse args and process. If we get a failure, free zval and return FALSE.
if (cluster_mset_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "MSET",
sizeof("MSET")-1, z_ret, cluster_mset_resp) ==-1)
{
efree(z_ret);
RETURN_FALSE;
}
}
/* {{{ proto array RedisCluster::msetnx(array keyvalues) */
PHP_METHOD(RedisCluster, msetnx) {
zval *z_ret = emalloc(sizeof(*z_ret));
array_init(z_ret);
// Parse args and process. If we get a failure, free mem and return FALSE
if (cluster_mset_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "MSETNX",
sizeof("MSETNX")-1, z_ret, cluster_msetnx_resp) ==-1)
{
zval_dtor(z_ret);
efree(z_ret);
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto bool RedisCluster::setex(string key, string value, int expiry) */
PHP_METHOD(RedisCluster, setex) {
CLUSTER_PROCESS_KW_CMD("SETEX", redis_key_long_val_cmd, cluster_bool_resp, 0);
}
/* }}} */
/* {{{ proto bool RedisCluster::psetex(string key, string value, int expiry) */
PHP_METHOD(RedisCluster, psetex) {
CLUSTER_PROCESS_KW_CMD("PSETEX", redis_key_long_val_cmd, cluster_bool_resp, 0);
}
/* }}} */
/* {{{ proto bool RedisCluster::setnx(string key, string value) */
PHP_METHOD(RedisCluster, setnx) {
CLUSTER_PROCESS_KW_CMD("SETNX", redis_kv_cmd, cluster_1_resp, 0);
}
/* }}} */
/* {{{ proto string RedisCluster::getSet(string key, string value) */
PHP_METHOD(RedisCluster, getset) {
CLUSTER_PROCESS_KW_CMD("GETSET", redis_kv_cmd, cluster_bulk_resp, 0);
}
/* }}} */
/* {{{ proto int RedisCluster::exists(string $key, string ...$more_keys) */
PHP_METHOD(RedisCluster, exists) {
CLUSTER_PROCESS_KW_CMD("EXISTS", redis_varkey_cmd, cluster_long_resp, 1);
}
/* }}} */
/* {{{ proto int RedisCluster::exists(string $key, string ...$more_keys) */
PHP_METHOD(RedisCluster, touch) {
CLUSTER_PROCESS_KW_CMD("TOUCH", redis_varkey_cmd, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto array Redis::keys(string pattern) */
PHP_METHOD(RedisCluster, keys) {
redisCluster *c = GET_CONTEXT();
redisClusterNode *node;
size_t pat_len;
char *pat, *cmd;
clusterReply *resp;
int i, cmd_len;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &pat, &pat_len)
== FAILURE)
{
RETURN_FALSE;
}
/* Prefix and then build our command */
cmd_len = redis_spprintf(c->flags, NULL, &cmd, "KEYS", "k", pat, pat_len);
array_init(return_value);
/* Treat as readonly */
c->readonly = CLUSTER_IS_ATOMIC(c);
/* Iterate over our known nodes */
ZEND_HASH_FOREACH_PTR(c->nodes, node) {
if (node == NULL) continue;
if (cluster_send_slot(c, node->slot, cmd, cmd_len, TYPE_MULTIBULK
) < 0)
{
php_error_docref(0, E_ERROR, "Can't send KEYS to %s:%d",
ZSTR_VAL(node->sock->host), node->sock->port);
zval_dtor(return_value);
efree(cmd);
RETURN_FALSE;
}
/* Ensure we can get a response */
resp = cluster_read_resp(c, 0);
if (!resp) {
php_error_docref(0, E_WARNING,
"Can't read response from %s:%d", ZSTR_VAL(node->sock->host),
node->sock->port);
continue;
}
/* Iterate keys, adding to our big array */
for(i = 0; i < resp->elements; i++) {
/* Skip non bulk responses, they should all be bulk */
if (resp->element[i]->type != TYPE_BULK) {
continue;
}
add_next_index_stringl(return_value, resp->element[i]->str,
resp->element[i]->len);
}
/* Free response, don't free data */
cluster_free_reply(resp, 1);
} ZEND_HASH_FOREACH_END();
efree(cmd);
}
/* }}} */
/* {{{ proto int RedisCluster::type(string key) */
PHP_METHOD(RedisCluster, type) {
CLUSTER_PROCESS_KW_CMD("TYPE", redis_key_cmd, cluster_type_resp, 1);
}
/* }}} */
/* {{{ proto string RedisCluster::pop(string key, [int count = 0]) */
PHP_METHOD(RedisCluster, lpop) {
CLUSTER_PROCESS_KW_CMD("LPOP", redis_pop_cmd, cluster_pop_resp, 0);
}
/* }}} */
PHP_METHOD(RedisCluster, lpos) {
CLUSTER_PROCESS_CMD(lpos, cluster_lpos_resp, 1);
}
/* {{{ proto string RedisCluster::rpop(string key, [int count = 0]) */
PHP_METHOD(RedisCluster, rpop) {
CLUSTER_PROCESS_KW_CMD("RPOP", redis_pop_cmd, cluster_pop_resp, 0);
}
/* }}} */
/* {{{ proto bool RedisCluster::lset(string key, long index, string val) */
PHP_METHOD(RedisCluster, lset) {
CLUSTER_PROCESS_KW_CMD("LSET", redis_key_long_val_cmd, cluster_bool_resp, 0);
}
/* }}} */
/* {{{ proto string RedisCluster::spop(string key) */
PHP_METHOD(RedisCluster, spop) {
if (ZEND_NUM_ARGS() == 1) {
CLUSTER_PROCESS_KW_CMD("SPOP", redis_key_cmd, cluster_bulk_resp, 0);
} else if (ZEND_NUM_ARGS() == 2) {
CLUSTER_PROCESS_KW_CMD("SPOP", redis_key_long_cmd, cluster_mbulk_resp, 0);
} else {
ZEND_WRONG_PARAM_COUNT();
}
}
/* }}} */
/* {{{ proto string|array RedisCluster::srandmember(string key, [long count]) */
PHP_METHOD(RedisCluster, srandmember) {
CLUSTER_PROCESS_CMD(srandmember, cluster_srandmember_resp, 1);
}
/* {{{ proto string RedisCluster::strlen(string key) */
PHP_METHOD(RedisCluster, strlen) {
CLUSTER_PROCESS_KW_CMD("STRLEN", redis_key_cmd, cluster_long_resp, 1);
}
/* {{{ proto long RedisCluster::lpush(string key, string val1, ... valN) */
PHP_METHOD(RedisCluster, lpush) {
CLUSTER_PROCESS_KW_CMD("LPUSH", redis_key_varval_cmd, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto long RedisCluster::rpush(string key, string val1, ... valN) */
PHP_METHOD(RedisCluster, rpush) {
CLUSTER_PROCESS_KW_CMD("RPUSH", redis_key_varval_cmd, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto array RedisCluster::blpop(string key1, ... keyN, long timeout) */
PHP_METHOD(RedisCluster, blpop) {
CLUSTER_PROCESS_KW_CMD("BLPOP", redis_blocking_pop_cmd, cluster_mbulk_resp, 0);
}
/* }}} */
/* {{{ proto array RedisCluster::brpop(string key1, ... keyN, long timeout */
PHP_METHOD(RedisCluster, brpop) {
CLUSTER_PROCESS_KW_CMD("BRPOP", redis_blocking_pop_cmd, cluster_mbulk_resp, 0);
}
/* }}} */
/* {{{ proto long RedisCluster::rpushx(string key, mixed value) */
PHP_METHOD(RedisCluster, rpushx) {
CLUSTER_PROCESS_KW_CMD("RPUSHX", redis_kv_cmd, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto long RedisCluster::lpushx(string key, mixed value) */
PHP_METHOD(RedisCluster, lpushx) {
CLUSTER_PROCESS_KW_CMD("LPUSHX", redis_kv_cmd, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto long RedisCluster::linsert(string k,string pos,mix pvt,mix val) */
PHP_METHOD(RedisCluster, linsert) {
CLUSTER_PROCESS_CMD(linsert, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto string RedisCluster::lindex(string key, long index) */
PHP_METHOD(RedisCluster, lindex) {
CLUSTER_PROCESS_KW_CMD("LINDEX", redis_key_long_cmd, cluster_bulk_resp, 0);
}
/* }}} */
/* {{{ proto long RedisCluster::lrem(string key, long count, string val) */
PHP_METHOD(RedisCluster, lrem) {
CLUSTER_PROCESS_CMD(lrem, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto string RedisCluster::rpoplpush(string key, string key) */
PHP_METHOD(RedisCluster, rpoplpush) {
CLUSTER_PROCESS_KW_CMD("RPOPLPUSH", redis_key_key_cmd, cluster_bulk_resp, 0);
}
/* }}} */
/* {{{ proto string RedisCluster::brpoplpush(string key, string key, long tm) */
PHP_METHOD(RedisCluster, brpoplpush) {
CLUSTER_PROCESS_CMD(brpoplpush, cluster_bulk_resp, 0);
}
/* }}} */
PHP_METHOD(RedisCluster, lmove) {
CLUSTER_PROCESS_KW_CMD("LMOVE", redis_lmove_cmd, cluster_bulk_resp, 0);
}
PHP_METHOD(RedisCluster, blmove) {
CLUSTER_PROCESS_KW_CMD("BLMOVE", redis_lmove_cmd, cluster_bulk_resp, 0);
}
/* {{{ proto long RedisCluster::llen(string key) */
PHP_METHOD(RedisCluster, llen) {
CLUSTER_PROCESS_KW_CMD("LLEN", redis_key_cmd, cluster_long_resp, 1);
}
/* }}} */
/* {{{ proto long RedisCluster::scard(string key) */
PHP_METHOD(RedisCluster, scard) {
CLUSTER_PROCESS_KW_CMD("SCARD", redis_key_cmd, cluster_long_resp, 1);
}
/* }}} */
/* {{{ proto array RedisCluster::smembers(string key) */
PHP_METHOD(RedisCluster, smembers) {
CLUSTER_PROCESS_KW_CMD("SMEMBERS", redis_key_cmd, cluster_mbulk_resp, 1);
}
/* }}} */
/* {{{ proto long RedisCluster::sismember(string key) */
PHP_METHOD(RedisCluster, sismember) {
CLUSTER_PROCESS_KW_CMD("SISMEMBER", redis_kv_cmd, cluster_1_resp, 1);
}
/* }}} */
/* {{{ proto array RedisCluster::smismember(string key, string member0, ...memberN) */
PHP_METHOD(RedisCluster, smismember) {
CLUSTER_PROCESS_KW_CMD("SMISMEMBER", redis_key_varval_cmd, cluster_variant_resp, 1);
}
/* }}} */
/* {{{ proto long RedisCluster::sadd(string key, string val1 [, ...]) */
PHP_METHOD(RedisCluster, sadd) {
CLUSTER_PROCESS_KW_CMD("SADD", redis_key_varval_cmd, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto long RedisCluster::saddarray(string key, array values) */
PHP_METHOD(RedisCluster, saddarray) {
CLUSTER_PROCESS_KW_CMD("SADD", redis_key_val_arr_cmd, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto long RedisCluster::srem(string key, string val1 [, ...]) */
PHP_METHOD(RedisCluster, srem) {
CLUSTER_PROCESS_KW_CMD("SREM", redis_key_varval_cmd, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto array RedisCluster::sunion(string key1, ... keyN) */
PHP_METHOD(RedisCluster, sunion) {
CLUSTER_PROCESS_KW_CMD("SUNION", redis_varkey_cmd, cluster_mbulk_resp, 0);
}
/* }}} */
/* {{{ proto long RedisCluster::sunionstore(string dst, string k1, ... kN) */
PHP_METHOD(RedisCluster, sunionstore) {
CLUSTER_PROCESS_KW_CMD("SUNIONSTORE", redis_varkey_cmd, cluster_long_resp, 0);
}
/* }}} */
/* {{{ ptoto array RedisCluster::sinter(string k1, ... kN) */
PHP_METHOD(RedisCluster, sinter) {
CLUSTER_PROCESS_KW_CMD("SINTER", redis_varkey_cmd, cluster_mbulk_resp, 0);
}
/* {{{ proto RedisCluster::sintercard(array $keys, int $count = -1) */
PHP_METHOD(RedisCluster, sintercard) {
CLUSTER_PROCESS_KW_CMD("SINTERCARD", redis_intercard_cmd, cluster_long_resp, 0);
}
/* }}} */
/* }}} */
/* {{{ ptoto long RedisCluster::sinterstore(string dst, string k1, ... kN) */
PHP_METHOD(RedisCluster, sinterstore) {
CLUSTER_PROCESS_KW_CMD("SINTERSTORE", redis_varkey_cmd, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto array RedisCluster::sdiff(string k1, ... kN) */
PHP_METHOD(RedisCluster, sdiff) {
CLUSTER_PROCESS_KW_CMD("SDIFF", redis_varkey_cmd, cluster_mbulk_resp, 1);
}
/* }}} */
/* {{{ proto long RedisCluster::sdiffstore(string dst, string k1, ... kN) */
PHP_METHOD(RedisCluster, sdiffstore) {
CLUSTER_PROCESS_KW_CMD("SDIFFSTORE", redis_varkey_cmd, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto bool RedisCluster::smove(sting src, string dst, string mem) */
PHP_METHOD(RedisCluster, smove) {
CLUSTER_PROCESS_CMD(smove, cluster_1_resp, 0);
}
/* }}} */
/* {{{ proto bool RedisCluster::persist(string key) */
PHP_METHOD(RedisCluster, persist) {
CLUSTER_PROCESS_KW_CMD("PERSIST", redis_key_cmd, cluster_1_resp, 0);
}
/* }}} */
/* {{{ proto long RedisCluster::ttl(string key) */
PHP_METHOD(RedisCluster, ttl) {
CLUSTER_PROCESS_KW_CMD("TTL", redis_key_cmd, cluster_long_resp, 1);
}
/* }}} */
/* {{{ proto long RedisCluster::pttl(string key) */
PHP_METHOD(RedisCluster, pttl) {
CLUSTER_PROCESS_KW_CMD("PTTL", redis_key_cmd, cluster_long_resp, 1);
}
/* }}} */
/* {{{ proto long RedisCluster::zcard(string key) */
PHP_METHOD(RedisCluster, zcard) {
CLUSTER_PROCESS_KW_CMD("ZCARD", redis_key_cmd, cluster_long_resp, 1);
}
/* }}} */
/* {{{ proto double RedisCluster::zscore(string key) */
PHP_METHOD(RedisCluster, zscore) {
CLUSTER_PROCESS_KW_CMD("ZSCORE", redis_kv_cmd, cluster_dbl_resp, 1);
}
/* }}} */
PHP_METHOD(RedisCluster, zmscore) {
CLUSTER_PROCESS_KW_CMD("ZMSCORE", redis_key_varval_cmd, cluster_mbulk_dbl_resp, 1);
}
/* {{{ proto long RedisCluster::zadd(string key,double score,string mem, ...) */
PHP_METHOD(RedisCluster, zadd) {
CLUSTER_PROCESS_CMD(zadd, cluster_zadd_resp, 0);
}
/* }}} */
/* {{{ proto double RedisCluster::zincrby(string key, double by, string mem) */
PHP_METHOD(RedisCluster, zincrby) {
CLUSTER_PROCESS_CMD(zincrby, cluster_dbl_resp, 0);
}
/* }}} */
/* {{{ proto RedisCluster::zremrangebyscore(string k, string s, string e) */
PHP_METHOD(RedisCluster, zremrangebyscore) {
CLUSTER_PROCESS_KW_CMD("ZREMRANGEBYSCORE", redis_key_str_str_cmd,
cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto RedisCluster::zcount(string key, string s, string e) */
PHP_METHOD(RedisCluster, zcount) {
CLUSTER_PROCESS_KW_CMD("ZCOUNT", redis_key_str_str_cmd, cluster_long_resp, 1);
}
/* }}} */
/* {{{ proto long RedisCluster::zrank(string key, mixed member) */
PHP_METHOD(RedisCluster, zrank) {
CLUSTER_PROCESS_KW_CMD("ZRANK", redis_kv_cmd, cluster_long_resp, 1);
}
/* }}} */
/* {{{ proto long RedisCluster::zrevrank(string key, mixed member) */
PHP_METHOD(RedisCluster, zrevrank) {
CLUSTER_PROCESS_KW_CMD("ZREVRANK", redis_kv_cmd, cluster_long_resp, 1);
}
/* }}} */
/* {{{ proto long RedisCluster::hlen(string key) */
PHP_METHOD(RedisCluster, hlen) {
CLUSTER_PROCESS_KW_CMD("HLEN", redis_key_cmd, cluster_long_resp, 1);
}
/* }}} */
/* {{{ proto array RedisCluster::hkeys(string key) */
PHP_METHOD(RedisCluster, hkeys) {
CLUSTER_PROCESS_KW_CMD("HKEYS", redis_key_cmd, cluster_mbulk_raw_resp, 1);
}
/* }}} */
/* {{{ proto array RedisCluster::hvals(string key) */
PHP_METHOD(RedisCluster, hvals) {
CLUSTER_PROCESS_KW_CMD("HVALS", redis_key_cmd, cluster_mbulk_resp, 1);
}
/* }}} */
/* {{{ proto string RedisCluster::hget(string key, string mem) */
PHP_METHOD(RedisCluster, hget) {
CLUSTER_PROCESS_KW_CMD("HGET", redis_key_str_cmd, cluster_bulk_resp, 1);
}
/* }}} */
/* {{{ proto bool RedisCluster::hset(string key, string mem, string val) */
PHP_METHOD(RedisCluster, hset) {
CLUSTER_PROCESS_CMD(hset, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto bool RedisCluster::hsetnx(string key, string mem, string val) */
PHP_METHOD(RedisCluster, hsetnx) {
CLUSTER_PROCESS_CMD(hsetnx, cluster_1_resp, 0);
}
/* }}} */
/* {{{ proto array RedisCluster::hgetall(string key) */
PHP_METHOD(RedisCluster, hgetall) {
CLUSTER_PROCESS_KW_CMD("HGETALL", redis_key_cmd,
cluster_mbulk_zipstr_resp, 1);
}
/* }}} */
/* {{{ proto bool RedisCluster::hexists(string key, string member) */
PHP_METHOD(RedisCluster, hexists) {
CLUSTER_PROCESS_KW_CMD("HEXISTS", redis_key_str_cmd, cluster_1_resp, 1);
}
/* }}} */
/* {{{ proto long RedisCluster::hincr(string key, string mem, long val) */
PHP_METHOD(RedisCluster, hincrby) {
CLUSTER_PROCESS_CMD(hincrby, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto double RedisCluster::hincrbyfloat(string k, string m, double v) */
PHP_METHOD(RedisCluster, hincrbyfloat) {
CLUSTER_PROCESS_CMD(hincrbyfloat, cluster_dbl_resp, 0);
}
/* }}} */
/* {{{ proto bool RedisCluster::hmset(string key, array key_vals) */
PHP_METHOD(RedisCluster, hmset) {
CLUSTER_PROCESS_CMD(hmset, cluster_bool_resp, 0);
}
/* }}} */
/* {{{ proto bool RedisCluster::hrandfield(string key, [array $options]) */
PHP_METHOD(RedisCluster, hrandfield) {
CLUSTER_PROCESS_CMD(hrandfield, cluster_hrandfield_resp, 1);
}
/* }}} */
/* {{{ proto long RedisCluster::hdel(string key, string mem1, ... memN) */
PHP_METHOD(RedisCluster, hdel) {
CLUSTER_PROCESS_CMD(hdel, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto array RedisCluster::hmget(string key, array members) */
PHP_METHOD(RedisCluster, hmget) {
CLUSTER_PROCESS_CMD(hmget, cluster_mbulk_assoc_resp, 1);
}
/* }}} */
/* {{{ proto array RedisCluster::hstrlen(string key, string field) */
PHP_METHOD(RedisCluster, hstrlen) {
CLUSTER_PROCESS_CMD(hstrlen, cluster_long_resp, 1);
}
/* }}} */
/* {{{ proto string RedisCluster::dump(string key) */
PHP_METHOD(RedisCluster, dump) {
CLUSTER_PROCESS_KW_CMD("DUMP", redis_key_cmd, cluster_bulk_raw_resp, 1);
}
/* {{{ proto long RedisCluster::incr(string key) */
PHP_METHOD(RedisCluster, incr) {
CLUSTER_PROCESS_CMD(incr, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto long RedisCluster::incrby(string key, long byval) */
PHP_METHOD(RedisCluster, incrby) {
CLUSTER_PROCESS_KW_CMD("INCRBY", redis_key_long_cmd, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto long RedisCluster::decr(string key) */
PHP_METHOD(RedisCluster, decr) {
CLUSTER_PROCESS_CMD(decr, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto long RedisCluster::decrby(string key, long byval) */
PHP_METHOD(RedisCluster, decrby) {
CLUSTER_PROCESS_KW_CMD("DECRBY", redis_key_long_cmd, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto double RedisCluster::incrbyfloat(string key, double val) */
PHP_METHOD(RedisCluster, incrbyfloat) {
CLUSTER_PROCESS_KW_CMD("INCRBYFLOAT", redis_key_dbl_cmd,
cluster_dbl_resp, 0);
}
/* }}} */
/* {{{ proto double RedisCluster::decrbyfloat(string key, double val) */
PHP_METHOD(RedisCluster, decrbyfloat) {
CLUSTER_PROCESS_KW_CMD("DECRBYFLOAT", redis_key_dbl_cmd,
cluster_dbl_resp, 0);
}
/* }}} */
/* {{{ proto bool RedisCluster::expire(string key, long sec) */
PHP_METHOD(RedisCluster, expire) {
CLUSTER_PROCESS_KW_CMD("EXPIRE", redis_expire_cmd, cluster_1_resp, 0);
}
/* }}} */
/* {{{ proto bool RedisCluster::expireat(string key, long ts) */
PHP_METHOD(RedisCluster, expireat) {
CLUSTER_PROCESS_KW_CMD("EXPIREAT", redis_expire_cmd, cluster_1_resp, 0);
}
/* {{{ proto bool RedisCluster::pexpire(string key, long ms) */
PHP_METHOD(RedisCluster, pexpire) {
CLUSTER_PROCESS_KW_CMD("PEXPIRE", redis_expire_cmd, cluster_1_resp, 0);
}
/* }}} */
/* {{{ proto bool RedisCluster::pexpireat(string key, long ts) */
PHP_METHOD(RedisCluster, pexpireat) {
CLUSTER_PROCESS_KW_CMD("PEXPIREAT", redis_expire_cmd, cluster_1_resp, 0);
}
/* }}} */
/* {{{ Redis::expiretime(string $key): int */
PHP_METHOD(RedisCluster, expiretime) {
CLUSTER_PROCESS_KW_CMD("EXPIRETIME", redis_key_cmd, cluster_long_resp, 1);
}
/* {{{ Redis::pexpiretime(string $key): int */
PHP_METHOD(RedisCluster, pexpiretime) {
CLUSTER_PROCESS_KW_CMD("PEXPIRETIME", redis_key_cmd, cluster_long_resp, 1);
}
/* {{{ proto long RedisCluster::append(string key, string val) */
PHP_METHOD(RedisCluster, append) {
CLUSTER_PROCESS_KW_CMD("APPEND", redis_kv_cmd, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto long RedisCluster::getbit(string key, long val) */
PHP_METHOD(RedisCluster, getbit) {
CLUSTER_PROCESS_KW_CMD("GETBIT", redis_key_long_cmd, cluster_long_resp, 1);
}
/* }}} */
/* {{{ proto long RedisCluster::setbit(string key, long offset, bool onoff) */
PHP_METHOD(RedisCluster, setbit) {
CLUSTER_PROCESS_CMD(setbit, cluster_long_resp, 0);
}
/* {{{ proto long RedisCluster::bitop(string op,string key,[string key2,...]) */
PHP_METHOD(RedisCluster, bitop)
{
CLUSTER_PROCESS_CMD(bitop, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto long RedisCluster::bitcount(string key, [int start, int end]) */
PHP_METHOD(RedisCluster, bitcount) {
CLUSTER_PROCESS_CMD(bitcount, cluster_long_resp, 1);
}
/* }}} */
/* {{{ proto long RedisCluster::bitpos(string key, int bit, [int s, int end]) */
PHP_METHOD(RedisCluster, bitpos) {
CLUSTER_PROCESS_CMD(bitpos, cluster_long_resp, 1);
}
/* }}} */
/* {{{ proto string Redis::lget(string key, long index) */
PHP_METHOD(RedisCluster, lget) {
CLUSTER_PROCESS_KW_CMD("LINDEX", redis_key_long_cmd, cluster_bulk_resp, 1);
}
/* }}} */
/* {{{ proto string RedisCluster::getrange(string key, long start, long end) */ PHP_METHOD(RedisCluster, getrange) {
CLUSTER_PROCESS_KW_CMD("GETRANGE", redis_key_long_long_cmd,
cluster_bulk_resp, 1);
}
/* }}} */
/* {{{ prot RedisCluster::lcs(string $key1, string $key2, ?array $options = NULL): mixed; */
PHP_METHOD(RedisCluster, lcs) {
CLUSTER_PROCESS_CMD(lcs, cluster_variant_resp, 1);
}
/* {{{ proto Redis|array|false Redis::lmpop(array $keys, string $from, int $count = 1) */
PHP_METHOD(RedisCluster, lmpop) {
CLUSTER_PROCESS_KW_CMD("LMPOP", redis_mpop_cmd, cluster_mpop_resp, 0);
}
/* }}} */
/* {{{ proto Redis|array|false Redis::blmpop(double $timeout, array $keys, string $from, int $count = 1) */
PHP_METHOD(RedisCluster, blmpop) {
CLUSTER_PROCESS_KW_CMD("BLMPOP", redis_mpop_cmd, cluster_mpop_resp, 0);
}
/* }}} */
/* {{{ proto Redis|array|false Redis::zmpop(array $keys, string $from, int $count = 1) */
PHP_METHOD(RedisCluster, zmpop) {
CLUSTER_PROCESS_KW_CMD("ZMPOP", redis_mpop_cmd, cluster_mpop_resp, 0);
}
/* }}} */
/* {{{ proto Redis|array|false Redis::bzmpop(double $timeout, array $keys, sring $from, int $count = 1) */
PHP_METHOD(RedisCluster, bzmpop) {
CLUSTER_PROCESS_KW_CMD("BZMPOP", redis_mpop_cmd, cluster_mpop_resp, 0);
}
/* }}} */
/* {{{ proto string RedisCluster::ltrim(string key, long start, long end) */
PHP_METHOD(RedisCluster, ltrim) {
CLUSTER_PROCESS_KW_CMD("LTRIM", redis_key_long_long_cmd, cluster_bool_resp, 0);
}
/* }}} */
/* {{{ proto array RedisCluster::lrange(string key, long start, long end) */
PHP_METHOD(RedisCluster, lrange) {
CLUSTER_PROCESS_KW_CMD("LRANGE", redis_key_long_long_cmd,
cluster_mbulk_resp, 1);
}
/* }}} */
/* {{{ proto long RedisCluster::zremrangebyrank(string k, long s, long e) */
PHP_METHOD(RedisCluster, zremrangebyrank) {
CLUSTER_PROCESS_KW_CMD("ZREMRANGEBYRANK", redis_key_long_long_cmd,
cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto long RedisCluster::publish(string key, string msg) */
PHP_METHOD(RedisCluster, publish) {
CLUSTER_PROCESS_KW_CMD("PUBLISH", redis_key_str_cmd, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto bool RedisCluster::rename(string key1, string key2) */
PHP_METHOD(RedisCluster, rename) {
CLUSTER_PROCESS_KW_CMD("RENAME", redis_key_key_cmd, cluster_bool_resp, 0);
}
/* }}} */
/* {{{ proto bool RedisCluster::renamenx(string key1, string key2) */
PHP_METHOD(RedisCluster, renamenx) {
CLUSTER_PROCESS_KW_CMD("RENAMENX", redis_key_key_cmd, cluster_1_resp, 0);
}
/* }}} */
/* {{{ proto long RedisCluster::pfcount(string key) */
PHP_METHOD(RedisCluster, pfcount) {
CLUSTER_PROCESS_CMD(pfcount, cluster_long_resp, 1);
}
/* }}} */
/* {{{ proto bool RedisCluster::pfadd(string key, array vals) */
PHP_METHOD(RedisCluster, pfadd) {
CLUSTER_PROCESS_CMD(pfadd, cluster_1_resp, 0);
}
/* }}} */
/* {{{ proto bool RedisCluster::pfmerge(string key, array keys) */
PHP_METHOD(RedisCluster, pfmerge) {
CLUSTER_PROCESS_CMD(pfmerge, cluster_bool_resp, 0);
}
/* }}} */
/* {{{ proto boolean RedisCluster::restore(string key, long ttl, string val) */
PHP_METHOD(RedisCluster, restore) {
CLUSTER_PROCESS_CMD(restore, cluster_bool_resp, 0);
}
/* }}} */
/* {{{ proto long RedisCluster::setrange(string key, long offset, string val) */
PHP_METHOD(RedisCluster, setrange) {
CLUSTER_PROCESS_KW_CMD("SETRANGE", redis_key_long_str_cmd,
cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto
* array RedisCluster::zrange(string k, long s, long e, bool score = 0) */
PHP_METHOD(RedisCluster, zrange) {
CLUSTER_PROCESS_KW_CMD("ZRANGE", redis_zrange_cmd, cluster_zrange_resp, 1);
}
/* }}} */
/* {{{ proto
* array RedisCluster::zrange(string $dstkey, string $srckey, long s, long e, array|bool $options = false) */
PHP_METHOD(RedisCluster, zrangestore) {
CLUSTER_PROCESS_KW_CMD("ZRANGESTORE", redis_zrange_cmd, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto
* array RedisCluster::zrevrange(string k,long s,long e,bool scores = 0) */
PHP_METHOD(RedisCluster, zrevrange) {
CLUSTER_PROCESS_KW_CMD("ZREVRANGE", redis_zrange_cmd, cluster_zrange_resp, 1);
}
/* }}} */
/* {{{ proto array
* RedisCluster::zrangebyscore(string k, long s, long e, array opts) */
PHP_METHOD(RedisCluster, zrangebyscore) {
CLUSTER_PROCESS_KW_CMD("ZRANGEBYSCORE", redis_zrange_cmd, cluster_zrange_resp, 1);
}
/* }}} */
/* {{{ proto RedisCluster::zunionstore(string dst, array keys, [array weights,
* string agg]) */
PHP_METHOD(RedisCluster, zunionstore) {
CLUSTER_PROCESS_KW_CMD("ZUNIONSTORE", redis_zinterunionstore_cmd, cluster_long_resp, 0);
}
/* }}} */
PHP_METHOD(RedisCluster, zdiff) {
CLUSTER_PROCESS_CMD(zdiff, cluster_zdiff_resp, 1);
}
PHP_METHOD(RedisCluster, zdiffstore) {
CLUSTER_PROCESS_CMD(zdiffstore, cluster_long_resp, 0);
}
PHP_METHOD(RedisCluster, zinter) {
CLUSTER_PROCESS_KW_CMD("ZUNION", redis_zinterunion_cmd, cluster_zdiff_resp, 1);
}
PHP_METHOD(RedisCluster, zunion) {
CLUSTER_PROCESS_KW_CMD("ZINTER", redis_zinterunion_cmd, cluster_zdiff_resp, 1);
}
/* {{{ proto array RedisCluster::zrandmember(string key, array options) */
PHP_METHOD(RedisCluster, zrandmember) {
CLUSTER_PROCESS_CMD(zrandmember, cluster_zrandmember_resp, 1);
}
/* }}} */
/* {{{ proto RedisCluster::zinterstore(string dst, array keys, [array weights,
* string agg]) */
PHP_METHOD(RedisCluster, zinterstore) {
CLUSTER_PROCESS_KW_CMD("ZINTERSTORE", redis_zinterunionstore_cmd, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto RedisCluster::zintercard(array $keys, int $count = -1) */
PHP_METHOD(RedisCluster, zintercard) {
CLUSTER_PROCESS_KW_CMD("ZINTERCARD", redis_intercard_cmd, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto RedisCluster::zrem(string key, string val1, ... valN) */
PHP_METHOD(RedisCluster, zrem) {
CLUSTER_PROCESS_KW_CMD("ZREM", redis_key_varval_cmd, cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto array
* RedisCluster::zrevrangebyscore(string k, long s, long e, array opts) */
PHP_METHOD(RedisCluster, zrevrangebyscore) {
CLUSTER_PROCESS_KW_CMD("ZREVRANGEBYSCORE", redis_zrange_cmd, cluster_zrange_resp, 1);
}
/* }}} */
/* {{{ proto array RedisCluster::zrangebylex(string key, string min, string max,
* [offset, count]) */
PHP_METHOD(RedisCluster, zrangebylex) {
CLUSTER_PROCESS_KW_CMD("ZRANGEBYLEX", redis_zrangebylex_cmd,
cluster_mbulk_resp, 1);
}
/* }}} */
/* {{{ proto array RedisCluster::zrevrangebylex(string key, string min,
* string min, [long off, long limit) */
PHP_METHOD(RedisCluster, zrevrangebylex) {
CLUSTER_PROCESS_KW_CMD("ZREVRANGEBYLEX", redis_zrangebylex_cmd,
cluster_mbulk_resp, 1);
}
/* }}} */
/* {{{ proto long RedisCluster::zlexcount(string key, string min, string max) */
PHP_METHOD(RedisCluster, zlexcount) {
CLUSTER_PROCESS_KW_CMD("ZLEXCOUNT", redis_gen_zlex_cmd, cluster_long_resp, 1);
}
/* }}} */
/* {{{ proto long RedisCluster::zremrangebylex(string key, string min, string max) */
PHP_METHOD(RedisCluster, zremrangebylex) {
CLUSTER_PROCESS_KW_CMD("ZREMRANGEBYLEX", redis_gen_zlex_cmd,
cluster_long_resp, 0);
}
/* }}} */
/* {{{ proto array RedisCluster::zpopmax(string key) */
PHP_METHOD(RedisCluster, zpopmax) {
if (ZEND_NUM_ARGS() == 1) {
CLUSTER_PROCESS_KW_CMD("ZPOPMAX", redis_key_cmd, cluster_mbulk_zipdbl_resp, 0);
} else if (ZEND_NUM_ARGS() == 2) {
CLUSTER_PROCESS_KW_CMD("ZPOPMAX", redis_key_long_cmd, cluster_mbulk_zipdbl_resp, 0);
} else {
ZEND_WRONG_PARAM_COUNT();
}
}
/* }}} */
/* {{{ proto array RedisCluster::zpopmin(string key) */
PHP_METHOD(RedisCluster, zpopmin) {
if (ZEND_NUM_ARGS() == 1) {
CLUSTER_PROCESS_KW_CMD("ZPOPMIN", redis_key_cmd, cluster_mbulk_zipdbl_resp, 0);
} else if (ZEND_NUM_ARGS() == 2) {
CLUSTER_PROCESS_KW_CMD("ZPOPMIN", redis_key_long_cmd, cluster_mbulk_zipdbl_resp, 0);
} else {
ZEND_WRONG_PARAM_COUNT();
}
}
/* }}} */
/* {{{ proto array RedisCluster::bzPopMin(Array keys [, timeout]) }}} */
PHP_METHOD(RedisCluster, bzpopmax) {
CLUSTER_PROCESS_KW_CMD("BZPOPMAX", redis_blocking_pop_cmd, cluster_mbulk_resp, 0);
}
/* {{{ proto array RedisCluster::bzPopMax(Array keys [, timeout]) }}} */
PHP_METHOD(RedisCluster, bzpopmin) {
CLUSTER_PROCESS_KW_CMD("BZPOPMIN", redis_blocking_pop_cmd, cluster_mbulk_resp, 0);
}
/* {{{ proto RedisCluster::sort(string key, array options) */
PHP_METHOD(RedisCluster, sort) {
CLUSTER_PROCESS_KW_CMD("SORT", redis_sort_cmd, cluster_variant_resp, 0);
}
/* {{{ proto RedisCluster::sort_ro(string key, array options) */
PHP_METHOD(RedisCluster, sort_ro) {
CLUSTER_PROCESS_KW_CMD("SORT_RO", redis_sort_cmd, cluster_variant_resp, 1);
}
/* {{{ proto RedisCluster::object(string subcmd, string key) */
PHP_METHOD(RedisCluster, object) {
CLUSTER_PROCESS_CMD(object, cluster_object_resp, 1);
}
/* {{{ proto null RedisCluster::subscribe(array chans, callable cb) */
PHP_METHOD(RedisCluster, subscribe) {
CLUSTER_PROCESS_KW_CMD("SUBSCRIBE", redis_subscribe_cmd, cluster_sub_resp, 0);
}
/* }}} */
/* {{{ proto null RedisCluster::psubscribe(array pats, callable cb) */
PHP_METHOD(RedisCluster, psubscribe) {
CLUSTER_PROCESS_KW_CMD("PSUBSCRIBE", redis_subscribe_cmd, cluster_sub_resp, 0);
}
/* }}} */
static void generic_unsub_cmd(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
char *kw)
{
char *cmd;
int cmd_len;
void *ctx;
short slot;
// There is not reason to unsubscribe outside of a subscribe loop
if (c->subscribed_slot == -1) {
php_error_docref(0, E_WARNING,
"You can't unsubscribe outside of a subscribe loop");
RETURN_FALSE;
}
// Call directly because we're going to set the slot manually
if (redis_unsubscribe_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags, kw,
&cmd, &cmd_len, &slot, &ctx)
== FAILURE)
{
RETURN_FALSE;
}
// This has to operate on our subscribe slot
if (cluster_send_slot(c, c->subscribed_slot, cmd, cmd_len, TYPE_MULTIBULK
) == FAILURE)
{
CLUSTER_THROW_EXCEPTION("Failed to UNSUBSCRIBE within our subscribe loop!", 0);
RETURN_FALSE;
}
// Now process response from the slot we're subscribed on
cluster_unsub_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, ctx);
// Cleanup our command
efree(cmd);
}
/* {{{ proto array RedisCluster::unsubscribe(array chans) */
PHP_METHOD(RedisCluster, unsubscribe) {
generic_unsub_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, GET_CONTEXT(),
"UNSUBSCRIBE");
}
/* }}} */
/* {{{ proto array RedisCluster::punsubscribe(array pats) */
PHP_METHOD(RedisCluster, punsubscribe) {
generic_unsub_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, GET_CONTEXT(),
"PUNSUBSCRIBE");
}
/* }}} */
/* {{{ proto mixed RedisCluster::eval(string script, [array args, int numkeys) */
PHP_METHOD(RedisCluster, eval) {
CLUSTER_PROCESS_KW_CMD("EVAL", redis_eval_cmd, cluster_variant_raw_resp, 0);
}
/* }}} */
/* {{{ proto mixed RedisCluster::eval_ro(string script, [array args, int numkeys) */
PHP_METHOD(RedisCluster, eval_ro) {
CLUSTER_PROCESS_KW_CMD("EVAL_RO", redis_eval_cmd, cluster_variant_raw_resp, 1);
}
/* }}} */
/* {{{ proto mixed RedisCluster::evalsha(string sha, [array args, int numkeys]) */
PHP_METHOD(RedisCluster, evalsha) {
CLUSTER_PROCESS_KW_CMD("EVALSHA", redis_eval_cmd, cluster_variant_raw_resp, 0);
}
/* }}} */
/* {{{ proto mixed RedisCluster::evalsha_ro(string sha, [array args, int numkeys]) */
PHP_METHOD(RedisCluster, evalsha_ro) {
CLUSTER_PROCESS_KW_CMD("EVALSHA_RO", redis_eval_cmd, cluster_variant_raw_resp, 1);
}
/* }}} */
/* Commands that do not interact with Redis, but just report stuff about
* various options, etc */
/* {{{ proto string RedisCluster::getmode() */
PHP_METHOD(RedisCluster, getmode) {
redisCluster *c = GET_CONTEXT();
RETURN_LONG(c->flags->mode);
}
/* }}} */
/* {{{ proto string RedisCluster::getlasterror() */
PHP_METHOD(RedisCluster, getlasterror) {
redisCluster *c = GET_CONTEXT();
if (c->err) {
RETURN_STRINGL(ZSTR_VAL(c->err), ZSTR_LEN(c->err));
}
RETURN_NULL();
}
/* }}} */
/* {{{ proto bool RedisCluster::clearlasterror() */
PHP_METHOD(RedisCluster, clearlasterror) {
redisCluster *c = GET_CONTEXT();
if (c->err) {
zend_string_release(c->err);
c->err = NULL;
}
RETURN_TRUE;
}
static void redisSumNodeBytes(redisClusterNode *node, zend_long *tx, zend_long *rx) {
struct redisClusterNode *slave;
*tx += node->sock->txBytes;
*rx += node->sock->rxBytes;
if (node->slaves) {
ZEND_HASH_FOREACH_PTR(node->slaves, slave) {
*tx += slave->sock->txBytes;
*rx += slave->sock->rxBytes;
} ZEND_HASH_FOREACH_END();
}
}
static void redisClearNodeBytes(redisClusterNode *node) {
struct redisClusterNode *slave;
node->sock->txBytes = 0;
node->sock->rxBytes = 0;
if (node->slaves) {
ZEND_HASH_FOREACH_PTR(node->slaves, slave) {
slave->sock->txBytes = 0;
slave->sock->rxBytes = 0;
} ZEND_HASH_FOREACH_END();
}
}
PHP_METHOD(RedisCluster, gettransferredbytes) {
redisCluster *c = GET_CONTEXT();
zend_long rx = 0, tx = 0;
redisClusterNode *node;
ZEND_HASH_FOREACH_PTR(c->nodes, node) {
redisSumNodeBytes(node, &tx, &rx);
} ZEND_HASH_FOREACH_END();
array_init_size(return_value, 2);
add_next_index_long(return_value, tx);
add_next_index_long(return_value, rx);
}
/* }}} */
PHP_METHOD(RedisCluster, cleartransferredbytes) {
redisCluster *c = GET_CONTEXT();
redisClusterNode *node;
ZEND_HASH_FOREACH_PTR(c->nodes, node) {
redisClearNodeBytes(node);
} ZEND_HASH_FOREACH_END();
}
/* {{{ proto long RedisCluster::getOption(long option */
PHP_METHOD(RedisCluster, getoption) {
redisCluster *c = GET_CONTEXT();
redis_getoption_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags, c);
}
/* }}} */
/* {{{ proto bool RedisCluster::setOption(long option, mixed value) */
PHP_METHOD(RedisCluster, setoption) {
redisCluster *c = GET_CONTEXT();
redis_setoption_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags, c);
}
/* }}} */
/* {{{ proto string RedisCluster::_prefix(string key) */
PHP_METHOD(RedisCluster, _prefix) {
redisCluster *c = GET_CONTEXT();
redis_prefix_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags);
}
/* }}} */
/* {{{ proto string RedisCluster::_serialize(mixed val) */
PHP_METHOD(RedisCluster, _serialize) {
redisCluster *c = GET_CONTEXT();
redis_serialize_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags);
}
/* }}} */
/* {{{ proto mixed RedisCluster::_unserialize(string val) */
PHP_METHOD(RedisCluster, _unserialize) {
redisCluster *c = GET_CONTEXT();
redis_unserialize_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU,
c->flags, redis_cluster_exception_ce);
}
/* }}} */
PHP_METHOD(RedisCluster, _compress) {
redisCluster *c = GET_CONTEXT();
redis_compress_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags);
}
PHP_METHOD(RedisCluster, _uncompress) {
redisCluster *c = GET_CONTEXT();
redis_uncompress_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags,
redis_cluster_exception_ce);
}
PHP_METHOD(RedisCluster, _pack) {
redisCluster *c = GET_CONTEXT();
redis_pack_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags);
}
PHP_METHOD(RedisCluster, _unpack) {
redisCluster *c = GET_CONTEXT();
redis_unpack_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags);
}
/* {{{ proto array RedisCluster::_masters() */
PHP_METHOD(RedisCluster, _masters) {
redisCluster *c = GET_CONTEXT();
redisClusterNode *node;
array_init(return_value);
ZEND_HASH_FOREACH_PTR(c->nodes, node) {
if (node == NULL) break;
zval z_sub;
array_init(&z_sub);
add_next_index_stringl(&z_sub, ZSTR_VAL(node->sock->host), ZSTR_LEN(node->sock->host));
add_next_index_long(&z_sub, node->sock->port);
add_next_index_zval(return_value, &z_sub);
} ZEND_HASH_FOREACH_END();
}
PHP_METHOD(RedisCluster, _redir) {
redisCluster *c = GET_CONTEXT();
char buf[255];
size_t len;
len = snprintf(buf, sizeof(buf), "%s:%d", c->redir_host, c->redir_port);
if (*c->redir_host && c->redir_host_len) {
RETURN_STRINGL(buf, len);
} else {
RETURN_NULL();
}
}
/*
* Transaction handling
*/
/* {{{ proto bool RedisCluster::multi() */
PHP_METHOD(RedisCluster, multi) {
redisCluster *c = GET_CONTEXT();
zend_long value = MULTI;
ZEND_PARSE_PARAMETERS_START(0, 1)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(value)
ZEND_PARSE_PARAMETERS_END();
if (value != MULTI) {
php_error_docref(NULL, E_WARNING, "RedisCluster does not support PIPELINING");
}
if (c->flags->mode == MULTI) {
php_error_docref(NULL, E_WARNING,
"RedisCluster is already in MULTI mode, ignoring");
RETURN_FALSE;
}
/* Flag that we're in MULTI mode */
c->flags->mode = MULTI;
c->flags->txBytes = 0;
c->flags->rxBytes = 0;
/* Return our object so we can chain MULTI calls */
RETVAL_ZVAL(getThis(), 1, 0);
}
/* {{{ proto bool RedisCluster::watch() */
PHP_METHOD(RedisCluster, watch) {
redisCluster *c = GET_CONTEXT();
HashTable *ht_dist;
clusterDistList *dl;
smart_string cmd = {0};
zval *z_args;
int argc = ZEND_NUM_ARGS(), i;
zend_ulong slot;
zend_string *zstr;
// Disallow in MULTI mode
if (c->flags->mode == MULTI) {
php_error_docref(NULL, E_WARNING,
"WATCH command not allowed in MULTI mode");
RETURN_FALSE;
}
// Don't need to process zero arguments
if (!argc) RETURN_FALSE;
// Create our distribution HashTable
ht_dist = cluster_dist_create();
// Allocate args, and grab them
z_args = emalloc(sizeof(zval) * argc);
if (zend_get_parameters_array(ht, argc, z_args) == FAILURE) {
efree(z_args);
cluster_dist_free(ht_dist);
RETURN_FALSE;
}
// Loop through arguments, prefixing if needed
for(i = 0 ; i < argc; i++) {
// We'll need the key as a string
zstr = zval_get_string(&z_args[i]);
// Add this key to our distribution handler
if (cluster_dist_add_key(c, ht_dist, ZSTR_VAL(zstr), ZSTR_LEN(zstr), NULL) == FAILURE) {
CLUSTER_THROW_EXCEPTION("Can't issue WATCH command as the keyspace isn't fully mapped", 0);
zend_string_release(zstr);
RETURN_FALSE;
}
zend_string_release(zstr);
}
// Iterate over each node we'll be sending commands to
ZEND_HASH_FOREACH_PTR(ht_dist, dl) {
// Grab the clusterDistList pointer itself
if (dl == NULL) {
CLUSTER_THROW_EXCEPTION("Internal error in a PHP HashTable", 0);
cluster_dist_free(ht_dist);
efree(z_args);
efree(cmd.c);
RETURN_FALSE;
} else if (zend_hash_get_current_key(ht_dist, NULL, &slot) != HASH_KEY_IS_LONG) {
break;
}
// Construct our watch command for this node
redis_cmd_init_sstr(&cmd, dl->len, "WATCH", sizeof("WATCH")-1);
for (i = 0; i < dl->len; i++) {
redis_cmd_append_sstr(&cmd, dl->entry[i].key,
dl->entry[i].key_len);
}
// If we get a failure from this, we have to abort
if (cluster_send_command(c,(short)slot,cmd.c,cmd.len) ==-1) {
RETURN_FALSE;
}
// This node is watching
SLOT_SOCK(c, (short)slot)->watching = 1;
// Zero out our command buffer
cmd.len = 0;
} ZEND_HASH_FOREACH_END();
// Cleanup
cluster_dist_free(ht_dist);
efree(z_args);
efree(cmd.c);
RETURN_TRUE;
}
/* {{{ proto bool RedisCluster::unwatch() */
PHP_METHOD(RedisCluster, unwatch) {
redisCluster *c = GET_CONTEXT();
short slot;
// Send UNWATCH to nodes that need it
for(slot = 0; slot < REDIS_CLUSTER_SLOTS; slot++) {
if (c->master[slot] && SLOT_SOCK(c,slot)->watching) {
if (cluster_send_slot(c, slot, RESP_UNWATCH_CMD,
sizeof(RESP_UNWATCH_CMD)-1,
TYPE_LINE) ==-1)
{
CLUSTER_RETURN_BOOL(c, 0);
}
// No longer watching
SLOT_SOCK(c,slot)->watching = 0;
}
}
CLUSTER_RETURN_BOOL(c, 1);
}
/* {{{ proto array RedisCluster::exec() */
PHP_METHOD(RedisCluster, exec) {
redisCluster *c = GET_CONTEXT();
clusterFoldItem *fi;
// Verify we are in fact in multi mode
if (CLUSTER_IS_ATOMIC(c)) {
php_error_docref(NULL, E_WARNING, "RedisCluster is not in MULTI mode");
RETURN_FALSE;
}
// First pass, send EXEC and abort on failure
fi = c->multi_head;
while (fi) {
if (SLOT_SOCK(c, fi->slot)->mode == MULTI) {
if ( cluster_send_exec(c, fi->slot) < 0) {
cluster_abort_exec(c);
CLUSTER_THROW_EXCEPTION("Error processing EXEC across the cluster", 0);
// Free our queue, reset MULTI state
CLUSTER_FREE_QUEUE(c);
CLUSTER_RESET_MULTI(c);
RETURN_FALSE;
}
SLOT_SOCK(c, fi->slot)->mode = ATOMIC;
SLOT_SOCK(c, fi->slot)->watching = 0;
}
fi = fi->next;
}
// MULTI multi-bulk response handler
cluster_multi_mbulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
// Free our callback queue, any enqueued distributed command context items
// and reset our MULTI state.
CLUSTER_FREE_QUEUE(c);
CLUSTER_RESET_MULTI(c);
}
/* {{{ proto bool RedisCluster::discard() */
PHP_METHOD(RedisCluster, discard) {
redisCluster *c = GET_CONTEXT();
if (CLUSTER_IS_ATOMIC(c)) {
php_error_docref(NULL, E_WARNING, "Cluster is not in MULTI mode");
RETURN_FALSE;
}
if (cluster_abort_exec(c) < 0) {
CLUSTER_RESET_MULTI(c);
}
CLUSTER_FREE_QUEUE(c);
RETURN_TRUE;
}
/* Get a slot either by key (string) or host/port array */
static short
cluster_cmd_get_slot(redisCluster *c, zval *z_arg)
{
size_t key_len;
int key_free;
zval *z_host, *z_port;
short slot;
char *key;
zend_string *zstr;
/* If it's a string, treat it as a key. Otherwise, look for a two
* element array */
if (Z_TYPE_P(z_arg) ==IS_STRING || Z_TYPE_P(z_arg) ==IS_LONG ||
Z_TYPE_P(z_arg) ==IS_DOUBLE)
{
/* Allow for any scalar here */
zstr = zval_get_string(z_arg);
key = ZSTR_VAL(zstr);
key_len = ZSTR_LEN(zstr);
/* Hash it */
key_free = redis_key_prefix(c->flags, &key, &key_len);
slot = cluster_hash_key(key, key_len);
zend_string_release(zstr);
if (key_free) efree(key);
} else if (Z_TYPE_P(z_arg) == IS_ARRAY &&
(z_host = zend_hash_index_find(Z_ARRVAL_P(z_arg), 0)) != NULL &&
(z_port = zend_hash_index_find(Z_ARRVAL_P(z_arg), 1)) != NULL &&
Z_TYPE_P(z_host) == IS_STRING && Z_TYPE_P(z_port) == IS_LONG
) {
/* Attempt to find this specific node by host:port */
slot = cluster_find_slot(c,(const char *)Z_STRVAL_P(z_host),
(unsigned short)Z_LVAL_P(z_port));
/* Inform the caller if they've passed bad data */
if (slot < 0) {
php_error_docref(0, E_WARNING, "Unknown node %s:" ZEND_LONG_FMT,
Z_STRVAL_P(z_host), Z_LVAL_P(z_port));
}
} else {
php_error_docref(0, E_WARNING,
"Directed commands must be passed a key or [host,port] array");
return -1;
}
return slot;
}
/* Generic handler for things we want directed at a given node, like SAVE,
* BGSAVE, FLUSHDB, FLUSHALL, etc */
static void
cluster_empty_node_cmd(INTERNAL_FUNCTION_PARAMETERS, char *kw,
REDIS_REPLY_TYPE reply_type, cluster_cb cb)
{
redisCluster *c = GET_CONTEXT();
char *cmd;
int cmd_len;
zval *z_arg;
short slot;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &z_arg) == FAILURE) {
RETURN_FALSE;
}
// One argument means find the node (treated like a key), and two means
// send the command to a specific host and port
slot = cluster_cmd_get_slot(c, z_arg);
if (slot < 0) {
RETURN_FALSE;
}
// Construct our command
cmd_len = redis_spprintf(NULL, NULL, &cmd, kw, "");
// Kick off our command
if (cluster_send_slot(c, slot, cmd, cmd_len, reply_type) < 0) {
CLUSTER_THROW_EXCEPTION("Unable to send command at a specific node", 0);
efree(cmd);
RETURN_FALSE;
}
// Our response callback
cb(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
// Free our command
efree(cmd);
}
static void
cluster_flush_cmd(INTERNAL_FUNCTION_PARAMETERS, char *kw, REDIS_REPLY_TYPE reply_type, cluster_cb cb)
{
redisCluster *c = GET_CONTEXT();
char *cmd;
int cmd_len;
zval *z_arg;
zend_bool async = 0;
short slot;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|b", &z_arg, &async) == FAILURE) {
RETURN_FALSE;
}
// One argument means find the node (treated like a key), and two means
// send the command to a specific host and port
slot = cluster_cmd_get_slot(c, z_arg);
if (slot < 0) {
RETURN_FALSE;
}
// Construct our command
if (async) {
cmd_len = redis_spprintf(NULL, NULL, &cmd, kw, "s", "ASYNC", sizeof("ASYNC") - 1);
} else {
cmd_len = redis_spprintf(NULL, NULL, &cmd, kw, "");
}
// Kick off our command
if (cluster_send_slot(c, slot, cmd, cmd_len, reply_type) < 0) {
CLUSTER_THROW_EXCEPTION("Unable to send command at a specific node", 0);
efree(cmd);
RETURN_FALSE;
}
// Our response callback
cb(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
// Free our command
efree(cmd);
}
/* Generic routine for handling various commands which need to be directed at
* a node, but have complex syntax. We simply parse out the arguments and send
* the command as constructed by the caller */
static void cluster_raw_cmd(INTERNAL_FUNCTION_PARAMETERS, char *kw, int kw_len)
{
redisCluster *c = GET_CONTEXT();
smart_string cmd = {0};
zval *z_args;
short slot;
int i, argc = ZEND_NUM_ARGS();
/* Commands using this pass-thru don't need to be enabled in MULTI mode */
if (!CLUSTER_IS_ATOMIC(c)) {
php_error_docref(0, E_WARNING,
"Command can't be issued in MULTI mode");
RETURN_FALSE;
}
/* We at least need the key or [host,port] argument */
if (argc < 1) {
php_error_docref(0, E_WARNING,
"Command requires at least an argument to direct to a node");
RETURN_FALSE;
}
/* Allocate an array to process arguments */
z_args = emalloc(argc * sizeof(zval));
/* Grab args */
if (zend_get_parameters_array(ht, argc, z_args) == FAILURE) {
efree(z_args);
RETURN_FALSE;
}
/* First argument needs to be the "where" */
if ((slot = cluster_cmd_get_slot(c, &z_args[0])) < 0) {
efree(z_args);
RETURN_FALSE;
}
/* Initialize our command */
redis_cmd_init_sstr(&cmd, argc-1, kw, kw_len);
/* Iterate, appending args */
for(i = 1; i < argc; i++) {
zend_string *zstr = zval_get_string(&z_args[i]);
redis_cmd_append_sstr(&cmd, ZSTR_VAL(zstr), ZSTR_LEN(zstr));
zend_string_release(zstr);
}
/* Send it off */
if (cluster_send_slot(c, slot, cmd.c, cmd.len, TYPE_EOF) < 0) {
CLUSTER_THROW_EXCEPTION("Couldn't send command to node", 0);
efree(cmd.c);
efree(z_args);
RETURN_FALSE;
}
/* Read the response variant */
cluster_variant_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
efree(cmd.c);
efree(z_args);
}
/* Generic method for HSCAN, SSCAN, and ZSCAN */
static void cluster_kscan_cmd(INTERNAL_FUNCTION_PARAMETERS,
REDIS_SCAN_TYPE type)
{
redisCluster *c = GET_CONTEXT();
char *cmd, *pat = NULL, *key = NULL;
size_t key_len = 0, pat_len = 0, pat_free = 0;
int cmd_len, key_free = 0;
short slot;
zval *z_it;
HashTable *hash;
long it, num_ele;
zend_long count = 0;
// Can't be in MULTI mode
if (!CLUSTER_IS_ATOMIC(c)) {
CLUSTER_THROW_EXCEPTION("SCAN type commands can't be called in MULTI mode!", 0);
RETURN_FALSE;
}
/* Parse arguments */
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/|s!l", &key,
&key_len, &z_it, &pat, &pat_len, &count) == FAILURE)
{
RETURN_FALSE;
}
/* Treat as readonly */
c->readonly = 1;
// Convert iterator to long if it isn't, update our long iterator if it's
// set and >0, and finish if it's back to zero
if (Z_TYPE_P(z_it) != IS_LONG || Z_LVAL_P(z_it) < 0) {
convert_to_long(z_it);
it = 0;
} else if (Z_LVAL_P(z_it) != 0) {
it = Z_LVAL_P(z_it);
} else {
RETURN_FALSE;
}
// Apply any key prefix we have, get the slot
key_free = redis_key_prefix(c->flags, &key, &key_len);
slot = cluster_hash_key(key, key_len);
if (c->flags->scan & REDIS_SCAN_PREFIX) {
pat_free = redis_key_prefix(c->flags, &pat, &pat_len);
}
// If SCAN_RETRY is set, loop until we get a zero iterator or until
// we get non-zero elements. Otherwise we just send the command once.
do {
/* Free our return value if we're back in the loop */
if (Z_TYPE_P(return_value) == IS_ARRAY) {
zval_dtor(return_value);
ZVAL_NULL(return_value);
}
// Create command
cmd_len = redis_fmt_scan_cmd(&cmd, type, key, key_len, it, pat, pat_len,
count);
// Send it off
if (cluster_send_command(c, slot, cmd, cmd_len) == FAILURE)
{
CLUSTER_THROW_EXCEPTION("Couldn't send SCAN command", 0);
if (key_free) efree(key);
efree(cmd);
RETURN_FALSE;
}
// Read response
if (cluster_scan_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, type,
&it) == FAILURE)
{
CLUSTER_THROW_EXCEPTION("Couldn't read SCAN response", 0);
if (key_free) efree(key);
efree(cmd);
RETURN_FALSE;
}
// Count the elements we got back
hash = Z_ARRVAL_P(return_value);
num_ele = zend_hash_num_elements(hash);
// Free our command
efree(cmd);
} while (c->flags->scan & REDIS_SCAN_RETRY && it != 0 && num_ele == 0);
// Free our pattern
if (pat_free) efree(pat);
// Free our key
if (key_free) efree(key);
// Update iterator reference
Z_LVAL_P(z_it) = it;
}
static int redis_acl_op_readonly(zend_string *op) {
/* Only return read-only for operations we know to be */
if (ZSTR_STRICMP_STATIC(op, "LIST") ||
ZSTR_STRICMP_STATIC(op, "USERS") ||
ZSTR_STRICMP_STATIC(op, "GETUSER") ||
ZSTR_STRICMP_STATIC(op, "CAT") ||
ZSTR_STRICMP_STATIC(op, "GENPASS") ||
ZSTR_STRICMP_STATIC(op, "WHOAMI") ||
ZSTR_STRICMP_STATIC(op, "LOG")) return 1;
return 0;
}
PHP_METHOD(RedisCluster, acl) {
redisCluster *c = GET_CONTEXT();
smart_string cmdstr = {0};
int argc = ZEND_NUM_ARGS(), i, readonly;
cluster_cb cb;
zend_string *zs;
zval *zargs;
void *ctx = NULL;
short slot;
/* ACL in cluster needs a slot argument, and then at least the op */
if (argc < 2) {
WRONG_PARAM_COUNT;
RETURN_FALSE;
}
/* Grab all our arguments and determine the command slot */
zargs = emalloc(argc * sizeof(*zargs));
if (zend_get_parameters_array(ht, argc, zargs) == FAILURE ||
(slot = cluster_cmd_get_slot(c, &zargs[0]) < 0))
{
efree(zargs);
RETURN_FALSE;
}
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc - 1, "ACL");
/* Read the op, determin if it's readonly, and add it */
zs = zval_get_string(&zargs[1]);
readonly = redis_acl_op_readonly(zs);
redis_cmd_append_sstr_zstr(&cmdstr, zs);
/* We have specialized handlers for GETUSER and LOG, whereas every
* other ACL command can be handled generically */
if (zend_string_equals_literal_ci(zs, "GETUSER")) {
cb = cluster_acl_getuser_resp;
} else if (zend_string_equals_literal_ci(zs, "LOG")) {
cb = cluster_acl_log_resp;
} else {
cb = cluster_variant_resp;
}
zend_string_release(zs);
/* Process remaining args */
for (i = 2; i < argc; i++) {
zs = zval_get_string(&zargs[i]);
redis_cmd_append_sstr_zstr(&cmdstr, zs);
zend_string_release(zs);
}
/* Can we use replicas? */
c->readonly = readonly && CLUSTER_IS_ATOMIC(c);
/* Kick off our command */
if (cluster_send_slot(c, slot, cmdstr.c, cmdstr.len, TYPE_EOF) < 0) {
CLUSTER_THROW_EXCEPTION("Unabler to send ACL command", 0);
efree(zargs);
RETURN_FALSE;
}
if (CLUSTER_IS_ATOMIC(c)) {
cb(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
} else {
CLUSTER_ENQUEUE_RESPONSE(c, slot, cb, ctx);
}
efree(cmdstr.c);
efree(zargs);
}
/* {{{ proto RedisCluster::scan(string master, long it [, string pat, long cnt]) */
PHP_METHOD(RedisCluster, scan) {
redisCluster *c = GET_CONTEXT();
char *cmd, *pat = NULL;
size_t pat_len = 0;
int cmd_len;
short slot;
zval *z_it, *z_node;
long it, num_ele, pat_free = 0;
zend_long count = 0;
/* Treat as read-only */
c->readonly = CLUSTER_IS_ATOMIC(c);
/* Can't be in MULTI mode */
if (!CLUSTER_IS_ATOMIC(c)) {
CLUSTER_THROW_EXCEPTION("SCAN type commands can't be called in MULTI mode", 0);
RETURN_FALSE;
}
/* Parse arguments */
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z/z|s!l", &z_it,
&z_node, &pat, &pat_len, &count) == FAILURE)
{
RETURN_FALSE;
}
/* Convert or update iterator */
if (Z_TYPE_P(z_it) != IS_LONG || Z_LVAL_P(z_it) < 0) {
convert_to_long(z_it);
it = 0;
} else if (Z_LVAL_P(z_it) != 0) {
it = Z_LVAL_P(z_it);
} else {
RETURN_FALSE;
}
if (c->flags->scan & REDIS_SCAN_PREFIX) {
pat_free = redis_key_prefix(c->flags, &pat, &pat_len);
}
/* With SCAN_RETRY on, loop until we get some keys, otherwise just return
* what Redis does, as it does */
do {
/* Free our return value if we're back in the loop */
if (Z_TYPE_P(return_value) == IS_ARRAY) {
zval_dtor(return_value);
ZVAL_NULL(return_value);
}
/* Construct our command */
cmd_len = redis_fmt_scan_cmd(&cmd, TYPE_SCAN, NULL, 0, it, pat, pat_len,
count);
if ((slot = cluster_cmd_get_slot(c, z_node)) < 0) {
RETURN_FALSE;
}
// Send it to the node in question
if (cluster_send_command(c, slot, cmd, cmd_len) < 0)
{
CLUSTER_THROW_EXCEPTION("Couldn't send SCAN to node", 0);
efree(cmd);
RETURN_FALSE;
}
if (cluster_scan_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, TYPE_SCAN,
&it) == FAILURE || Z_TYPE_P(return_value)!=IS_ARRAY)
{
CLUSTER_THROW_EXCEPTION("Couldn't process SCAN response from node", 0);
efree(cmd);
RETURN_FALSE;
}
efree(cmd);
num_ele = zend_hash_num_elements(Z_ARRVAL_P(return_value));
} while (c->flags->scan & REDIS_SCAN_RETRY && it != 0 && num_ele == 0);
if (pat_free) efree(pat);
Z_LVAL_P(z_it) = it;
}
/* }}} */
/* {{{ proto RedisCluster::sscan(string key, long it [string pat, long cnt]) */
PHP_METHOD(RedisCluster, sscan) {
cluster_kscan_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, TYPE_SSCAN);
}
/* }}} */
/* {{{ proto RedisCluster::zscan(string key, long it [string pat, long cnt]) */
PHP_METHOD(RedisCluster, zscan) {
cluster_kscan_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, TYPE_ZSCAN);
}
/* }}} */
/* {{{ proto RedisCluster::hscan(string key, long it [string pat, long cnt]) */
PHP_METHOD(RedisCluster, hscan) {
cluster_kscan_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, TYPE_HSCAN);
}
/* }}} */
/* {{{ proto RedisCluster::save(string key)
* proto RedisCluster::save(array host_port) */
PHP_METHOD(RedisCluster, save) {
cluster_empty_node_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "SAVE", TYPE_LINE,
cluster_bool_resp);
}
/* }}} */
/* {{{ proto RedisCluster::bgsave(string key)
* proto RedisCluster::bgsave(array host_port) */
PHP_METHOD(RedisCluster, bgsave) {
cluster_empty_node_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "BGSAVE",
TYPE_LINE, cluster_bool_resp);
}
/* }}} */
/* {{{ proto RedisCluster::flushdb(string key, [bool async])
* proto RedisCluster::flushdb(array host_port, [bool async]) */
PHP_METHOD(RedisCluster, flushdb) {
cluster_flush_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "FLUSHDB",
TYPE_LINE, cluster_bool_resp);
}
/* }}} */
/* {{{ proto RedisCluster::flushall(string key, [bool async])
* proto RedisCluster::flushall(array host_port, [bool async]) */
PHP_METHOD(RedisCluster, flushall) {
cluster_flush_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "FLUSHALL",
TYPE_LINE, cluster_bool_resp);
}
/* }}} */
/* {{{ proto RedisCluster::dbsize(string key)
* proto RedisCluster::dbsize(array host_port) */
PHP_METHOD(RedisCluster, dbsize) {
cluster_empty_node_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "DBSIZE",
TYPE_INT, cluster_long_resp);
}
/* }}} */
/* {{{ proto RedisCluster::bgrewriteaof(string key)
* proto RedisCluster::bgrewriteaof(array host_port) */
PHP_METHOD(RedisCluster, bgrewriteaof) {
cluster_empty_node_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "BGREWRITEAOF",
TYPE_LINE, cluster_bool_resp);
}
/* }}} */
/* {{{ proto RedisCluster::lastsave(string key)
* proto RedisCluster::lastsave(array $host_port) */
PHP_METHOD(RedisCluster, lastsave) {
cluster_empty_node_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "LASTSAVE",
TYPE_INT, cluster_long_resp);
}
/* }}} */
/* {{{ proto array RedisCluster::info(string key, [string $arg])
* proto array RedisCluster::info(array host_port, [string $arg]) */
PHP_METHOD(RedisCluster, info) {
redisCluster *c = GET_CONTEXT();
zval *node = NULL, *args = NULL;
smart_string cmdstr = {0};
REDIS_REPLY_TYPE rtype;
zend_string *section;
void *ctx = NULL;
int i, argc;
short slot;
ZEND_PARSE_PARAMETERS_START(1, -1)
Z_PARAM_ZVAL(node)
Z_PARAM_OPTIONAL
Z_PARAM_VARIADIC('*', args, argc)
ZEND_PARSE_PARAMETERS_END();
if ((slot = cluster_cmd_get_slot(c, node)) < 0)
RETURN_FALSE;
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc, "INFO");
/* Direct this command at the master */
c->readonly = 0;
for (i = 0; i < argc; i++) {
section = zval_get_string(&args[i]);
redis_cmd_append_sstr_zstr(&cmdstr, section);
zend_string_release(section);
}
rtype = CLUSTER_IS_ATOMIC(c) ? TYPE_BULK : TYPE_LINE;
if (cluster_send_slot(c, slot, cmdstr.c, cmdstr.len, rtype) < 0) {
CLUSTER_THROW_EXCEPTION("Unable to send INFO command to specific node", 0);
efree(cmdstr.c);
RETURN_FALSE;
}
if (CLUSTER_IS_ATOMIC(c)) {
cluster_info_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
} else {
CLUSTER_ENQUEUE_RESPONSE(c, slot, cluster_info_resp, ctx);
}
efree(cmdstr.c);
}
/* }}} */
/* {{{ proto array RedisCluster::client('list')
* proto bool RedisCluster::client('kill', $ipport)
* proto bool RedisCluster::client('setname', $name)
* proto string RedisCluster::client('getname')
*/
PHP_METHOD(RedisCluster, client) {
redisCluster *c = GET_CONTEXT();
char *cmd, *opt = NULL, *arg = NULL;
int cmd_len;
size_t opt_len, arg_len = 0;
REDIS_REPLY_TYPE rtype;
zval *z_node;
short slot;
cluster_cb cb;
/* Parse args */
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zs|s", &z_node, &opt,
&opt_len, &arg, &arg_len) == FAILURE)
{
RETURN_FALSE;
}
/* Make sure we can properly resolve the slot */
slot = cluster_cmd_get_slot(c, z_node);
if (slot < 0) RETURN_FALSE;
/* Our return type and reply callback is different for all subcommands */
if (opt_len == 4 && !strncasecmp(opt, "list", 4)) {
rtype = CLUSTER_IS_ATOMIC(c) ? TYPE_BULK : TYPE_LINE;
cb = cluster_client_list_resp;
} else if ((opt_len == 4 && !strncasecmp(opt, "kill", 4)) ||
(opt_len == 7 && !strncasecmp(opt, "setname", 7)))
{
rtype = TYPE_LINE;
cb = cluster_bool_resp;
} else if (opt_len == 7 && !strncasecmp(opt, "getname", 7)) {
rtype = CLUSTER_IS_ATOMIC(c) ? TYPE_BULK : TYPE_LINE;
cb = cluster_bulk_resp;
} else {
php_error_docref(NULL, E_WARNING,
"Invalid CLIENT subcommand (LIST, KILL, GETNAME, and SETNAME are valid");
RETURN_FALSE;
}
/* Construct the command */
if (ZEND_NUM_ARGS() == 3) {
cmd_len = redis_spprintf(NULL, NULL, &cmd, "CLIENT", "ss",
opt, opt_len, arg, arg_len);
} else if (ZEND_NUM_ARGS() == 2) {
cmd_len = redis_spprintf(NULL, NULL, &cmd, "CLIENT", "s",
opt, opt_len);
} else {
zend_wrong_param_count();
RETURN_FALSE;
}
/* Attempt to write our command */
if (cluster_send_slot(c, slot, cmd, cmd_len, rtype) < 0) {
CLUSTER_THROW_EXCEPTION("Unable to send CLIENT command to specific node", 0);
efree(cmd);
RETURN_FALSE;
}
/* Now enqueue or process response */
if (CLUSTER_IS_ATOMIC(c)) {
cb(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
} else {
void *ctx = NULL;
CLUSTER_ENQUEUE_RESPONSE(c, slot, cb, ctx);
}
efree(cmd);
}
/* {{{ proto mixed RedisCluster::cluster(variant) */
PHP_METHOD(RedisCluster, cluster) {
cluster_raw_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "CLUSTER",
sizeof("CLUSTER")-1);
}
/* }}} */
/* }}} */
/* {{{ proto mixed RedisCluster::config(string key, ...)
* proto mixed RedisCluster::config(array host_port, ...) */
PHP_METHOD(RedisCluster, config) {
cluster_raw_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "CONFIG",
sizeof("CONFIG")-1);
}
/* }}} */
/* {{{ proto mixed RedisCluster::pubsub(string key, ...)
* proto mixed RedisCluster::pubsub(array host_port, ...) */
PHP_METHOD(RedisCluster, pubsub) {
cluster_raw_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "PUBSUB",
sizeof("PUBSUB")-1);
}
/* }}} */
/* {{{ proto mixed RedisCluster::script(string key, ...)
* proto mixed RedisCluster::script(array host_port, ...) */
PHP_METHOD(RedisCluster, script) {
redisCluster *c = GET_CONTEXT();
smart_string cmd = {0};
zval *z_args;
short slot;
int argc = ZEND_NUM_ARGS();
/* Commands using this pass-thru don't need to be enabled in MULTI mode */
if (!CLUSTER_IS_ATOMIC(c)) {
php_error_docref(0, E_WARNING,
"Command can't be issued in MULTI mode");
RETURN_FALSE;
}
/* We at least need the key or [host,port] argument */
if (argc < 2) {
php_error_docref(0, E_WARNING,
"Command requires at least an argument to direct to a node");
RETURN_FALSE;
}
/* Allocate an array to process arguments */
z_args = ecalloc(argc, sizeof(zval));
/* Grab args */
if (zend_get_parameters_array(ht, argc, z_args) == FAILURE ||
(slot = cluster_cmd_get_slot(c, &z_args[0])) < 0 ||
redis_build_script_cmd(&cmd, argc - 1, &z_args[1]) == NULL
) {
efree(z_args);
RETURN_FALSE;
}
/* Send it off */
if (cluster_send_slot(c, slot, cmd.c, cmd.len, TYPE_EOF) < 0) {
CLUSTER_THROW_EXCEPTION("Couldn't send command to node", 0);
efree(cmd.c);
efree(z_args);
RETURN_FALSE;
}
/* Read the response variant */
cluster_variant_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
efree(cmd.c);
efree(z_args);
}
/* }}} */
/* {{{ proto mixed RedisCluster::slowlog(string key, ...)
* proto mixed RedisCluster::slowlog(array host_port, ...) */
PHP_METHOD(RedisCluster, slowlog) {
cluster_raw_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "SLOWLOG",
sizeof("SLOWLOG")-1);
}
/* }}} */
/* {{{ proto int RedisCluster::geoadd(string key, float long float lat string mem, ...) */
PHP_METHOD(RedisCluster, geoadd) {
CLUSTER_PROCESS_CMD(geoadd, cluster_long_resp, 0);
}
/* {{{ proto array RedisCluster::geohash(string key, string mem1, [string mem2...]) */
PHP_METHOD(RedisCluster, geohash) {
CLUSTER_PROCESS_KW_CMD("GEOHASH", redis_key_varval_cmd, cluster_mbulk_raw_resp, 1);
}
/* {{{ proto array RedisCluster::geopos(string key, string mem1, [string mem2...]) */
PHP_METHOD(RedisCluster, geopos) {
CLUSTER_PROCESS_KW_CMD("GEOPOS", redis_key_varval_cmd, cluster_variant_resp, 1);
}
/* {{{ proto array RedisCluster::geodist(string key, string mem1, string mem2 [string unit]) */
PHP_METHOD(RedisCluster, geodist) {
CLUSTER_PROCESS_CMD(geodist, cluster_dbl_resp, 1);
}
/* {{{ proto array RedisCluster::georadius() }}} */
PHP_METHOD(RedisCluster, georadius) {
CLUSTER_PROCESS_KW_CMD("GEORADIUS", redis_georadius_cmd, cluster_variant_resp, 1);
}
/* {{{ proto array RedisCluster::georadius() }}} */
PHP_METHOD(RedisCluster, georadius_ro) {
CLUSTER_PROCESS_KW_CMD("GEORADIUS_RO", redis_georadius_cmd, cluster_variant_resp, 1);
}
/* {{{ proto array RedisCluster::georadiusbymember() }}} */
PHP_METHOD(RedisCluster, georadiusbymember) {
CLUSTER_PROCESS_KW_CMD("GEORADIUSBYMEMBER", redis_georadiusbymember_cmd, cluster_variant_resp, 1);
}
/* {{{ proto array RedisCluster::georadiusbymember() }}} */
PHP_METHOD(RedisCluster, georadiusbymember_ro) {
CLUSTER_PROCESS_KW_CMD("GEORADIUSBYMEMBER_RO", redis_georadiusbymember_cmd, cluster_variant_resp, 1);
}
PHP_METHOD(RedisCluster, geosearch) {
CLUSTER_PROCESS_CMD(geosearch, cluster_geosearch_resp, 1);
}
PHP_METHOD(RedisCluster, geosearchstore) {
CLUSTER_PROCESS_CMD(geosearchstore, cluster_long_resp, 0);
}
/* {{{ proto array RedisCluster::role(string key)
* proto array RedisCluster::role(array host_port) */
PHP_METHOD(RedisCluster, role) {
cluster_empty_node_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "ROLE",
TYPE_MULTIBULK, cluster_variant_resp);
}
/* {{{ proto array RedisCluster::time(string key)
* proto array RedisCluster::time(array host_port) */
PHP_METHOD(RedisCluster, time) {
cluster_empty_node_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "TIME",
TYPE_MULTIBULK, cluster_variant_resp);
}
/* }}} */
/* {{{ proto string RedisCluster::randomkey(string key)
* proto string RedisCluster::randomkey(array host_port) */
PHP_METHOD(RedisCluster, randomkey) {
cluster_empty_node_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "RANDOMKEY",
TYPE_BULK, cluster_bulk_resp);
}
/* }}} */
/* {{{ proto bool RedisCluster::ping(string key| string msg)
* proto bool RedisCluster::ping(array host_port| string msg) */
PHP_METHOD(RedisCluster, ping) {
redisCluster *c = GET_CONTEXT();
REDIS_REPLY_TYPE rtype;
void *ctx = NULL;
zval *z_node;
char *cmd, *arg = NULL;
int cmdlen;
size_t arglen;
short slot;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|s!", &z_node, &arg,
&arglen) == FAILURE)
{
RETURN_FALSE;
}
/* Treat this as a readonly command */
c->readonly = CLUSTER_IS_ATOMIC(c);
/* Grab slot either by key or host/port */
slot = cluster_cmd_get_slot(c, z_node);
if (slot < 0) {
RETURN_FALSE;
}
/* Construct our command */
if (arg != NULL) {
cmdlen = redis_spprintf(NULL, NULL, &cmd, "PING", "s", arg, arglen);
} else {
cmdlen = redis_spprintf(NULL, NULL, &cmd, "PING", "");
}
/* Send it off */
rtype = CLUSTER_IS_ATOMIC(c) && arg != NULL ? TYPE_BULK : TYPE_LINE;
if (cluster_send_slot(c, slot, cmd, cmdlen, rtype) < 0) {
CLUSTER_THROW_EXCEPTION("Unable to send command at the specified node", 0);
efree(cmd);
RETURN_FALSE;
}
/* We're done with our command */
efree(cmd);
/* Process response */
if (CLUSTER_IS_ATOMIC(c)) {
if (arg != NULL) {
cluster_bulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
} else {
/* If we're atomic and didn't send an argument then we have already
* processed the reply (which must have been successful. */
RETURN_TRUE;
}
} else {
if (arg != NULL) {
CLUSTER_ENQUEUE_RESPONSE(c, slot, cluster_bulk_resp, ctx);
} else {
CLUSTER_ENQUEUE_RESPONSE(c, slot, cluster_variant_resp, ctx);
}
RETURN_ZVAL(getThis(), 1, 0);
}
}
/* }}} */
/* {{{ proto long RedisCluster::xack(string key, string group, array ids) }}} */
PHP_METHOD(RedisCluster, xack) {
CLUSTER_PROCESS_CMD(xack, cluster_long_resp, 0);
}
/* {{{ proto string RedisCluster::xadd(string key, string id, array field_values) }}} */
PHP_METHOD(RedisCluster, xadd) {
CLUSTER_PROCESS_CMD(xadd, cluster_bulk_raw_resp, 0);
}
/* {{{ proto array RedisCluster::xclaim(string key, string group, string consumer,
* long min_idle_time, array ids, array options) */
PHP_METHOD(RedisCluster, xclaim) {
CLUSTER_PROCESS_CMD(xclaim, cluster_xclaim_resp, 0);
}
PHP_METHOD(RedisCluster, xautoclaim) {
CLUSTER_PROCESS_CMD(xautoclaim, cluster_xclaim_resp, 0);
}
PHP_METHOD(RedisCluster, xdel) {
CLUSTER_PROCESS_KW_CMD("XDEL", redis_key_str_arr_cmd, cluster_long_resp, 0);
}
/* {{{ proto variant RedisCluster::xgroup(string op, [string key, string arg1, string arg2]) }}} */
PHP_METHOD(RedisCluster, xgroup) {
CLUSTER_PROCESS_CMD(xgroup, cluster_variant_resp, 0);
}
/* {{{ proto variant RedisCluster::xinfo(string op, [string arg1, string arg2]); */
PHP_METHOD(RedisCluster, xinfo) {
CLUSTER_PROCESS_CMD(xinfo, cluster_xinfo_resp, 0);
}
/* {{{ proto string RedisCluster::xlen(string key) }}} */
PHP_METHOD(RedisCluster, xlen) {
CLUSTER_PROCESS_KW_CMD("XLEN", redis_key_cmd, cluster_long_resp, 1);
}
PHP_METHOD(RedisCluster, xpending) {
CLUSTER_PROCESS_CMD(xpending, cluster_variant_resp_strings, 1);
}
PHP_METHOD(RedisCluster, xrange) {
CLUSTER_PROCESS_KW_CMD("XRANGE", redis_xrange_cmd, cluster_xrange_resp, 1);
}
PHP_METHOD(RedisCluster, xrevrange) {
CLUSTER_PROCESS_KW_CMD("XREVRANGE", redis_xrange_cmd, cluster_xrange_resp, 1);
}
PHP_METHOD(RedisCluster, xread) {
CLUSTER_PROCESS_CMD(xread, cluster_xread_resp, 1);
}
PHP_METHOD(RedisCluster, xreadgroup) {
CLUSTER_PROCESS_CMD(xreadgroup, cluster_xread_resp, 0);
}
PHP_METHOD(RedisCluster, xtrim) {
CLUSTER_PROCESS_CMD(xtrim, cluster_long_resp, 0);
}
/* {{{ proto string RedisCluster::echo(string key, string msg)
* proto string RedisCluster::echo(array host_port, string msg) */
PHP_METHOD(RedisCluster, echo) {
redisCluster *c = GET_CONTEXT();
REDIS_REPLY_TYPE rtype;
zval *z_arg;
char *cmd, *msg;
int cmd_len;
size_t msg_len;
short slot;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zs", &z_arg, &msg,
&msg_len) == FAILURE)
{
RETURN_FALSE;
}
/* Treat this as a readonly command */
c->readonly = CLUSTER_IS_ATOMIC(c);
/* Grab slot either by key or host/port */
slot = cluster_cmd_get_slot(c, z_arg);
if (slot < 0) {
RETURN_FALSE;
}
/* Construct our command */
cmd_len = redis_spprintf(NULL, NULL, &cmd, "ECHO", "s", msg, msg_len);
/* Send it off */
rtype = CLUSTER_IS_ATOMIC(c) ? TYPE_BULK : TYPE_LINE;
if (cluster_send_slot(c,slot,cmd,cmd_len,rtype) < 0) {
CLUSTER_THROW_EXCEPTION("Unable to send command at the specified node", 0);
efree(cmd);
RETURN_FALSE;
}
/* Process bulk response */
if (CLUSTER_IS_ATOMIC(c)) {
cluster_bulk_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
} else {
void *ctx = NULL;
CLUSTER_ENQUEUE_RESPONSE(c, slot, cluster_bulk_resp, ctx);
}
efree(cmd);
}
/* }}} */
/* {{{ proto mixed RedisCluster::rawcommand(string $key, string $cmd, [ $argv1 .. $argvN])
* proto mixed RedisCluster::rawcommand(array $host_port, string $cmd, [ $argv1 .. $argvN]) */
PHP_METHOD(RedisCluster, rawcommand) {
REDIS_REPLY_TYPE rtype;
int argc = ZEND_NUM_ARGS(), cmd_len;
redisCluster *c = GET_CONTEXT();
char *cmd = NULL;
zval *z_args;
short slot;
/* Sanity check on our arguments */
if (argc < 2) {
php_error_docref(NULL, E_WARNING,
"You must pass at least node information as well as at least a command.");
RETURN_FALSE;
}
z_args = emalloc(argc * sizeof(zval));
if (zend_get_parameters_array(ht, argc, z_args) == FAILURE) {
php_error_docref(NULL, E_WARNING,
"Internal PHP error parsing method parameters.");
efree(z_args);
RETURN_FALSE;
} else if (redis_build_raw_cmd(&z_args[1], argc-1, &cmd, &cmd_len) ||
(slot = cluster_cmd_get_slot(c, &z_args[0])) < 0)
{
if (cmd) efree(cmd);
efree(z_args);
RETURN_FALSE;
}
/* Free argument array */
efree(z_args);
/* Direct the command */
rtype = CLUSTER_IS_ATOMIC(c) ? TYPE_EOF : TYPE_LINE;
if (cluster_send_slot(c,slot,cmd,cmd_len,rtype) < 0) {
CLUSTER_THROW_EXCEPTION("Unable to send command to the specified node", 0);
efree(cmd);
RETURN_FALSE;
}
/* Process variant response */
if (CLUSTER_IS_ATOMIC(c)) {
cluster_variant_raw_resp(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
} else {
void *ctx = NULL;
CLUSTER_ENQUEUE_RESPONSE(c, slot, cluster_variant_raw_resp, ctx);
}
efree(cmd);
}
/* }}} */
/* {{{ proto array RedisCluster::command()
* proto array RedisCluster::command('INFO', string cmd)
* proto array RedisCluster::command('GETKEYS', array cmd_args) */
PHP_METHOD(RedisCluster, command) {
CLUSTER_PROCESS_CMD(command, cluster_variant_resp, 0);
}
PHP_METHOD(RedisCluster, copy) {
CLUSTER_PROCESS_CMD(copy, cluster_1_resp, 0)
}
/* vim: set tabstop=4 softtabstop=4 expandtab shiftwidth=4: */
redis-6.0.2/redis_cluster.h 0000644 0001750 0000012 00000006630 14515245367 016445 0 ustar pyatsukhnenko wheel #ifndef REDIS_CLUSTER_H
#define REDIS_CLUSTER_H
#include "cluster_library.h"
#include
#include
/* Get attached object context */
#define GET_CONTEXT() PHPREDIS_ZVAL_GET_OBJECT(redisCluster, getThis())
/* Command building/processing is identical for every command */
#define CLUSTER_BUILD_CMD(name, c, cmd, cmd_len, slot) \
redis_##name##_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags, &cmd, \
&cmd_len, &slot)
/* Append information required to handle MULTI commands to the tail of our MULTI
* linked list. */
#define CLUSTER_ENQUEUE_RESPONSE(c, slot, cb, ctx) \
clusterFoldItem *_item; \
_item = emalloc(sizeof(clusterFoldItem)); \
_item->callback = cb; \
_item->slot = slot; \
_item->ctx = ctx; \
_item->next = NULL; \
if(c->multi_head == NULL) { \
c->multi_head = _item; \
c->multi_curr = _item; \
} else { \
c->multi_curr->next = _item; \
c->multi_curr = _item; \
} \
/* Simple macro to free our enqueued callbacks after we EXEC */
#define CLUSTER_FREE_QUEUE(c) \
clusterFoldItem *_item = c->multi_head, *_tmp; \
while(_item) { \
_tmp = _item->next; \
efree(_item); \
_item = _tmp; \
} \
c->multi_head = c->multi_curr = NULL; \
/* Reset anything flagged as MULTI */
#define CLUSTER_RESET_MULTI(c) \
redisClusterNode *_node; \
ZEND_HASH_FOREACH_PTR(c->nodes, _node) { \
if (_node == NULL) break; \
_node->sock->watching = 0; \
_node->sock->mode = ATOMIC; \
} ZEND_HASH_FOREACH_END(); \
c->flags->watching = 0; \
c->flags->mode = ATOMIC; \
/* Simple 1-1 command -> response macro */
#define CLUSTER_PROCESS_CMD(cmdname, resp_func, readcmd) \
redisCluster *c = GET_CONTEXT(); \
c->readonly = CLUSTER_IS_ATOMIC(c) && readcmd; \
char *cmd; int cmd_len; short slot; void *ctx=NULL; \
if(redis_##cmdname##_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU,c->flags, &cmd, \
&cmd_len, &slot, &ctx)==FAILURE) { \
RETURN_FALSE; \
} \
if(cluster_send_command(c,slot,cmd,cmd_len)<0 || c->err!=NULL) {\
efree(cmd); \
RETURN_FALSE; \
} \
efree(cmd); \
if(c->flags->mode == MULTI) { \
CLUSTER_ENQUEUE_RESPONSE(c, slot, resp_func, ctx); \
RETURN_ZVAL(getThis(), 1, 0); \
} \
resp_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, ctx);
/* More generic processing, where only the keyword differs */
#define CLUSTER_PROCESS_KW_CMD(kw, cmdfunc, resp_func, readcmd) \
redisCluster *c = GET_CONTEXT(); \
c->readonly = CLUSTER_IS_ATOMIC(c) && readcmd; \
char *cmd; int cmd_len; short slot; void *ctx=NULL; \
if(cmdfunc(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags, kw, &cmd, &cmd_len,\
&slot,&ctx)==FAILURE) { \
RETURN_FALSE; \
} \
if(cluster_send_command(c,slot,cmd,cmd_len)<0 || c->err!=NULL) { \
efree(cmd); \
RETURN_FALSE; \
} \
efree(cmd); \
if(c->flags->mode == MULTI) { \
CLUSTER_ENQUEUE_RESPONSE(c, slot, resp_func, ctx); \
RETURN_ZVAL(getThis(), 1, 0); \
} \
resp_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, ctx);
extern zend_class_entry *redis_cluster_ce;
extern zend_class_entry *redis_cluster_exception_ce;
extern PHP_MINIT_FUNCTION(redis_cluster);
extern zend_object * create_cluster_context(zend_class_entry *class_type);
extern void free_cluster_context(zend_object *object);
#endif
redis-6.0.2/redis_cluster.stub.php 0000644 0001750 0000012 00000101106 14515245367 017753 0 ustar pyatsukhnenko wheel = 7.0.0 you may pass multiple optional sections.
*
* @see https://redis.io/commands/info/
*
* @param string|array $key_or_address Either a key name or array with host and port indicating
* which cluster node we want to send the command to.
* @param string $sections Optional section(s) you wish Redis server to return.
*
* @return RedisCluster|array|false
*/
public function info(string|array $key_or_address, string ...$sections): RedisCluster|array|false;
/**
* @see Redis::keys
*/
public function keys(string $pattern): RedisCluster|array|false;
/**
* @see Redis::lastsave
*/
public function lastsave(string|array $key_or_address): RedisCluster|int|false;
/**
* @see Redis::lget
*/
public function lget(string $key, int $index): RedisCluster|string|bool;
/**
* @see Redis::lindex
*/
public function lindex(string $key, int $index): mixed;
/**
* @see Redis::linsert
*/
public function linsert(string $key, string $pos, mixed $pivot, mixed $value): RedisCluster|int|false;
/**
* @see Redis::llen
*/
public function llen(string $key): RedisCluster|int|bool;
/**
* @see Redis::lpop
*/
public function lpop(string $key, int $count = 0): RedisCluster|bool|string|array;
/**
* @see Redis::lpos
*/
public function lpos(string $key, mixed $value, ?array $options = null): Redis|null|bool|int|array;
/**
* @see Redis::lpush
*/
public function lpush(string $key, mixed $value, mixed ...$other_values): RedisCluster|int|bool;
/**
* @see Redis::lpushx
*/
public function lpushx(string $key, mixed $value): RedisCluster|int|bool;
/**
* @see Redis::lrange
*/
public function lrange(string $key, int $start, int $end): RedisCluster|array|false;
/**
* @see Redis::lrem
*/
public function lrem(string $key, mixed $value, int $count = 0): RedisCluster|int|bool;
/**
* @see Redis::lset
*/
public function lset(string $key, int $index, mixed $value): RedisCluster|bool;
/**
* @see Redis::ltrim
*/
public function ltrim(string $key, int $start, int $end): RedisCluster|bool;
/**
* @see Redis::mget
*/
public function mget(array $keys): RedisCluster|array|false;
/**
* @see Redis::mset
*/
public function mset(array $key_values): RedisCluster|bool;
/**
* @see Redis::msetnx
*/
public function msetnx(array $key_values): RedisCluster|array|false;
/* We only support Redis::MULTI in RedisCluster but take the argument
so we can test MULTI..EXEC with RedisTest.php and in the event
we add pipeline support in the future. */
public function multi(int $value = Redis::MULTI): RedisCluster|bool;
/**
* @see Redis::object
*/
public function object(string $subcommand, string $key): RedisCluster|int|string|false;
/**
* @see Redis::persist
*/
public function persist(string $key): RedisCluster|bool;
/**
* @see Redis::pexpire
*/
public function pexpire(string $key, int $timeout, ?string $mode = null): RedisCluster|bool;
/**
* @see Redis::pexpireat
*/
public function pexpireat(string $key, int $timestamp, ?string $mode = null): RedisCluster|bool;
/**
* @see Redis::pfadd()
*/
public function pfadd(string $key, array $elements): RedisCluster|bool;
/**
* @see Redis::pfcount()
*/
public function pfcount(string $key): RedisCluster|int|false;
/**
* @see Redis::pfmerge()
*/
public function pfmerge(string $key, array $keys): RedisCluster|bool;
/**
* PING an instance in the redis cluster.
*
* @see Redis::ping()
*
* @param string|array $key_or_address Either a key name or a two element array with host and
* address, informing RedisCluster which node to ping.
*
* @param string $message An optional message to send.
*
* @return mixed This method always returns `true` if no message was sent, and the message itself
* if one was.
*/
public function ping(string|array $key_or_address, ?string $message = null): mixed;
/**
* @see Redis::psetex
*/
public function psetex(string $key, int $timeout, string $value): RedisCluster|bool;
/**
* @see Redis::psubscribe
*/
public function psubscribe(array $patterns, callable $callback): void;
/**
* @see Redis::pttl
*/
public function pttl(string $key): RedisCluster|int|false;
/**
* @see Redis::publish
*/
public function publish(string $channel, string $message): RedisCluster|bool;
/**
* @see Redis::pubsub
*/
public function pubsub(string|array $key_or_address, string ...$values): mixed;
/**
* @see Redis::punsubscribe
*/
public function punsubscribe(string $pattern, string ...$other_patterns): bool|array;
/**
* @see Redis::randomkey
*/
public function randomkey(string|array $key_or_address): RedisCluster|bool|string;
/**
* @see Redis::rawcommand
*/
public function rawcommand(string|array $key_or_address, string $command, mixed ...$args): mixed;
/**
* @see Redis::rename
*/
public function rename(string $key_src, string $key_dst): RedisCluster|bool;
/**
* @see Redis::renamenx
*/
public function renamenx(string $key, string $newkey): RedisCluster|bool;
/**
* @see Redis::restore
*/
public function restore(string $key, int $timeout, string $value, ?array $options = null): RedisCluster|bool;
/**
* @see Redis::role
*/
public function role(string|array $key_or_address): mixed;
/**
* @see Redis::rpop()
*/
public function rpop(string $key, int $count = 0): RedisCluster|bool|string|array;
/**
* @see Redis::rpoplpush()
*/
public function rpoplpush(string $src, string $dst): RedisCluster|bool|string;
/**
* @see Redis::rpush
*/
public function rpush(string $key, mixed ...$elements): RedisCluster|int|false;
/**
* @see Redis::rpushx
*/
public function rpushx(string $key, string $value): RedisCluster|bool|int;
/**
* @see Redis::sadd()
*/
public function sadd(string $key, mixed $value, mixed ...$other_values): RedisCluster|int|false;
/**
* @see Redis::saddarray()
*/
public function saddarray(string $key, array $values): RedisCluster|bool|int;
/**
* @see Redis::save
*/
public function save(string|array $key_or_address): RedisCluster|bool;
/**
* @see Redis::scan
*/
public function scan(?int &$iterator, string|array $key_or_address, ?string $pattern = null, int $count = 0): bool|array;
/**
* @see Redis::scard
*/
public function scard(string $key): RedisCluster|int|false;
/**
* @see Redis::script
*/
public function script(string|array $key_or_address, mixed ...$args): mixed;
/**
* @see Redis::sdiff()
*/
public function sdiff(string $key, string ...$other_keys): RedisCluster|array|false;
/**
* @see Redis::sdiffstore()
*/
public function sdiffstore(string $dst, string $key, string ...$other_keys): RedisCluster|int|false;
/**
* @see https://redis.io/commands/set
*/
public function set(string $key, mixed $value, mixed $options = null): RedisCluster|string|bool;
/**
* @see Redis::setbit
*/
public function setbit(string $key, int $offset, bool $onoff): RedisCluster|int|false;
/**
* @see Redis::setex
*/
public function setex(string $key, int $expire, mixed $value): RedisCluster|bool;
/**
* @see Redis::setnx
*/
public function setnx(string $key, mixed $value): RedisCluster|bool;
/**
* @see Redis::setoption
*/
public function setoption(int $option, mixed $value): bool;
/**
* @see Redis::setrange
*/
public function setrange(string $key, int $offset, string $value): RedisCluster|int|false;
/**
* @see Redis::sinter()
*/
public function sinter(array|string $key, string ...$other_keys): RedisCluster|array|false;
/**
* @see Redis::sintercard
*/
public function sintercard(array $keys, int $limit = -1): RedisCluster|int|false;
/**
* @see Redis::sinterstore()
*/
public function sinterstore(array|string $key, string ...$other_keys): RedisCluster|int|false;
/**
* @see Redis::sismember
*/
public function sismember(string $key, mixed $value): RedisCluster|bool;
/**
* @see Redis::smismember
*/
public function smismember(string $key, string $member, string ...$other_members): RedisCluster|array|false;
/**
* @see Redis::slowlog
*/
public function slowlog(string|array $key_or_address, mixed ...$args): mixed;
/**
* @see Redis::smembers()
*/
public function smembers(string $key): RedisCluster|array|false;
/**
* @see Redis::smove()
*/
public function smove(string $src, string $dst, string $member): RedisCluster|bool;
/**
* @see Redis::sort()
*/
public function sort(string $key, ?array $options = null): RedisCluster|array|bool|int|string;
/**
* @see Redis::sort_ro()
*/
public function sort_ro(string $key, ?array $options = null): RedisCluster|array|bool|int|string;
/**
* @see Redis::spop
*/
public function spop(string $key, int $count = 0): RedisCluster|string|array|false;
/**
* @see Redis::srandmember
*/
public function srandmember(string $key, int $count = 0): RedisCluster|string|array|false;
/**
* @see Redis::srem
*/
public function srem(string $key, mixed $value, mixed ...$other_values): RedisCluster|int|false;
/**
* @see Redis::sscan
*/
public function sscan(string $key, ?int &$iterator, ?string $pattern = null, int $count = 0): array|false;
/**
* @see Redis::strlen
*/
public function strlen(string $key): RedisCluster|int|false;
/**
* @see Redis::subscribe
*/
public function subscribe(array $channels, callable $cb): void;
/**
* @see Redis::sunion()
*/
public function sunion(string $key, string ...$other_keys): RedisCluster|bool|array;
/**
* @see Redis::sunionstore()
*/
public function sunionstore(string $dst, string $key, string ...$other_keys): RedisCluster|int|false;
/**
* @see Redis::time
*/
public function time(string|array $key_or_address): RedisCluster|bool|array;
/**
* @see Redis::ttl
*/
public function ttl(string $key): RedisCluster|int|false;
/**
* @see Redis::type
*/
public function type(string $key): RedisCluster|int|false;
/**
* @see Redis::unsubscribe
*/
public function unsubscribe(array $channels): bool|array;
/**
* @see Redis::unlink
*/
public function unlink(array|string $key, string ...$other_keys): RedisCluster|int|false;
/**
* @see Redis::unwatch
*/
public function unwatch(): bool;
/**
* @see Redis::watch
*/
public function watch(string $key, string ...$other_keys): RedisCluster|bool;
/**
* @see Redis::xack
*/
public function xack(string $key, string $group, array $ids): RedisCluster|int|false;
/**
* @see Redis::xadd
*/
public function xadd(string $key, string $id, array $values, int $maxlen = 0, bool $approx = false): RedisCluster|string|false;
/**
* @see Redis::xclaim
*/
public function xclaim(string $key, string $group, string $consumer, int $min_iddle, array $ids, array $options): RedisCluster|string|array|false;
/**
* @see Redis::xdel
*/
public function xdel(string $key, array $ids): RedisCluster|int|false;
/**
* @see Redis::xgroup
*/
public function xgroup(string $operation, ?string $key = null, ?string $group = null, ?string $id_or_consumer = null,
bool $mkstream = false, int $entries_read = -2): mixed;
/**
* @see Redis::xautoclaim
*/
public function xautoclaim(string $key, string $group, string $consumer, int $min_idle, string $start, int $count = -1, bool $justid = false): RedisCluster|bool|array;
/**
* @see Redis::xinfo
*/
public function xinfo(string $operation, ?string $arg1 = null, ?string $arg2 = null, int $count = -1): mixed;
/**
* @see Redis::xlen
*/
public function xlen(string $key): RedisCluster|int|false;
/**
* @see Redis::xpending
*/
public function xpending(string $key, string $group, ?string $start = null, ?string $end = null, int $count = -1, ?string $consumer = null): RedisCluster|array|false;
/**
* @see Redis::xrange
*/
public function xrange(string $key, string $start, string $end, int $count = -1): RedisCluster|bool|array;
/**
* @see Redis::xread
*/
public function xread(array $streams, int $count = -1, int $block = -1): RedisCluster|bool|array;
/**
* @see Redis::xreadgroup
*/
public function xreadgroup(string $group, string $consumer, array $streams, int $count = 1, int $block = 1): RedisCluster|bool|array;
/**
* @see Redis::xrevrange
*/
public function xrevrange(string $key, string $start, string $end, int $count = -1): RedisCluster|bool|array;
/**
* @see Redis::xtrim
*/
public function xtrim(string $key, int $maxlen, bool $approx = false, bool $minid = false, int $limit = -1): RedisCluster|int|false;
/**
* @see Redis::zadd
*/
public function zadd(string $key, array|float $score_or_options, mixed ...$more_scores_and_mems): RedisCluster|int|float|false;
/**
* @see Redis::zcard
*/
public function zcard(string $key): RedisCluster|int|false;
/**
* @see Redis::zcount
*/
public function zcount(string $key, string $start, string $end): RedisCluster|int|false;
/**
* @see Redis::zincrby
*/
public function zincrby(string $key, float $value, string $member): RedisCluster|float|false;
/**
* @see Redis::zinterstore
*/
public function zinterstore(string $dst, array $keys, ?array $weights = null, ?string $aggregate = null): RedisCluster|int|false;
/**
* @see Redis::zintercard
*/
public function zintercard(array $keys, int $limit = -1): RedisCluster|int|false;
/**
* @see Redis::zlexcount
*/
public function zlexcount(string $key, string $min, string $max): RedisCluster|int|false;
/**
* @see Redis::zpopmax
*/
public function zpopmax(string $key, ?int $value = null): RedisCluster|bool|array;
/**
* @see Redis::zpopmin
*/
public function zpopmin(string $key, ?int $value = null): RedisCluster|bool|array;
/**
* @see Redis::zrange
*/
public function zrange(string $key, mixed $start, mixed $end, array|bool|null $options = null): RedisCluster|array|bool;
/**
* @see Redis::zrangestore
*/
public function zrangestore(string $dstkey, string $srckey, int $start, int $end,
array|bool|null $options = null): RedisCluster|int|false;
/**
* @see https://redis.io/commands/zRandMember
*/
public function zrandmember(string $key, ?array $options = null): RedisCluster|string|array;
/**
* @see Redis::zrangebylex
*/
public function zrangebylex(string $key, string $min, string $max, int $offset = -1, int $count = -1): RedisCluster|array|false;
/**
* @see Redis::zrangebyscore
*/
public function zrangebyscore(string $key, string $start, string $end, array $options = []): RedisCluster|array|false;
/**
* @see Redis::zrank
*/
public function zrank(string $key, mixed $member): RedisCluster|int|false;
/**
* @see Redis::zrem
*/
public function zrem(string $key, string $value, string ...$other_values): RedisCluster|int|false;
/**
* @see Redis::zremrangebylex
*/
public function zremrangebylex(string $key, string $min, string $max): RedisCluster|int|false;
/**
* @see Redis::zremrangebyrank
*/
public function zremrangebyrank(string $key, string $min, string $max): RedisCluster|int|false;
/**
* @see Redis::zremrangebyscore
*/
public function zremrangebyscore(string $key, string $min, string $max): RedisCluster|int|false;
/**
* @see Redis::zrevrange
*/
public function zrevrange(string $key, string $min, string $max, ?array $options = null): RedisCluster|bool|array;
/**
* @see Redis::zrevrangebylex
*/
public function zrevrangebylex(string $key, string $min, string $max, ?array $options = null): RedisCluster|bool|array;
/**
* @see Redis::zrevrangebyscore
*/
public function zrevrangebyscore(string $key, string $min, string $max, ?array $options = null): RedisCluster|bool|array;
/**
* @see Redis::zrevrank
*/
public function zrevrank(string $key, mixed $member): RedisCluster|int|false;
/**
* @see Redis::zscan
*/
public function zscan(string $key, ?int &$iterator, ?string $pattern = null, int $count = 0): RedisCluster|bool|array;
/**
* @see Redis::zscore
*/
public function zscore(string $key, mixed $member): RedisCluster|float|false;
/**
* @see https://redis.io/commands/zMscore
*/
public function zmscore(string $key, mixed $member, mixed ...$other_members): Redis|array|false;
/**
* @see Redis::zunionstore
*/
public function zunionstore(string $dst, array $keys, ?array $weights = null, ?string $aggregate = null): RedisCluster|int|false;
/**
* @see https://redis.io/commands/zinter
*/
public function zinter(array $keys, ?array $weights = null, ?array $options = null): RedisCluster|array|false;
/**
* @see https://redis.io/commands/zdiffstore
*/
public function zdiffstore(string $dst, array $keys): RedisCluster|int|false;
/**
* @see https://redis.io/commands/zunion
*/
public function zunion(array $keys, ?array $weights = null, ?array $options = null): RedisCluster|array|false;
/**
* @see https://redis.io/commands/zdiff
*/
public function zdiff(array $keys, ?array $options = null): RedisCluster|array|false;
}
class RedisClusterException extends RuntimeException {}
redis-6.0.2/redis_cluster_arginfo.h 0000644 0001750 0000012 00000233511 14515245367 020152 0 ustar pyatsukhnenko wheel /* This is a generated file, edit the .stub.php file instead.
* Stub hash: 32b24ce215ff4f2299dd838fab7cbc36b81b65eb */
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster___construct, 0, 0, 1)
ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 1)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, seeds, IS_ARRAY, 1, "null")
ZEND_ARG_TYPE_MASK(0, timeout, MAY_BE_LONG|MAY_BE_DOUBLE, "0")
ZEND_ARG_TYPE_MASK(0, read_timeout, MAY_BE_LONG|MAY_BE_DOUBLE, "0")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, persistent, _IS_BOOL, 0, "false")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, auth, IS_MIXED, 0, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, context, IS_ARRAY, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster__compress, 0, 1, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster__uncompress arginfo_class_RedisCluster__compress
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_RedisCluster__serialize, 0, 1, MAY_BE_BOOL|MAY_BE_STRING)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster__unserialize, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster__pack, 0, 1, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster__unpack arginfo_class_RedisCluster__unserialize
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_RedisCluster__prefix, 0, 1, MAY_BE_BOOL|MAY_BE_STRING)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster__masters, 0, 0, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster__redir, 0, 0, IS_STRING, 1)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_acl, 0, 2, IS_MIXED, 0)
ZEND_ARG_TYPE_MASK(0, key_or_address, MAY_BE_STRING|MAY_BE_ARRAY, NULL)
ZEND_ARG_TYPE_INFO(0, subcmd, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, args, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_append, 0, 2, RedisCluster, MAY_BE_BOOL|MAY_BE_LONG)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_bgrewriteaof, 0, 1, RedisCluster, MAY_BE_BOOL)
ZEND_ARG_TYPE_MASK(0, key_or_address, MAY_BE_STRING|MAY_BE_ARRAY, NULL)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_bgsave arginfo_class_RedisCluster_bgrewriteaof
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_bitcount, 0, 1, RedisCluster, MAY_BE_BOOL|MAY_BE_LONG)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, start, IS_LONG, 0, "0")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, end, IS_LONG, 0, "-1")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, bybit, _IS_BOOL, 0, "false")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_bitop, 0, 3, RedisCluster, MAY_BE_BOOL|MAY_BE_LONG)
ZEND_ARG_TYPE_INFO(0, operation, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, deskey, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, srckey, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, otherkeys, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_bitpos, 0, 2, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, bit, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, start, IS_LONG, 0, "0")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, end, IS_LONG, 0, "-1")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, bybit, _IS_BOOL, 0, "false")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_blpop, 0, 2, RedisCluster, MAY_BE_ARRAY|MAY_BE_NULL|MAY_BE_FALSE)
ZEND_ARG_TYPE_MASK(0, key, MAY_BE_STRING|MAY_BE_ARRAY, NULL)
ZEND_ARG_TYPE_MASK(0, timeout_or_key, MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_LONG, NULL)
ZEND_ARG_VARIADIC_TYPE_INFO(0, extra_args, IS_MIXED, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_brpop arginfo_class_RedisCluster_blpop
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_brpoplpush, 0, 3, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, srckey, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, deskey, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, timeout, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_lmove, 0, 4, Redis, MAY_BE_STRING|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, src, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, wherefrom, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, whereto, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_blmove, 0, 5, Redis, MAY_BE_STRING|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, src, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, wherefrom, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, whereto, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, timeout, IS_DOUBLE, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_bzpopmax, 0, 2, IS_ARRAY, 0)
ZEND_ARG_TYPE_MASK(0, key, MAY_BE_STRING|MAY_BE_ARRAY, NULL)
ZEND_ARG_TYPE_MASK(0, timeout_or_key, MAY_BE_STRING|MAY_BE_LONG, NULL)
ZEND_ARG_VARIADIC_TYPE_INFO(0, extra_args, IS_MIXED, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_bzpopmin arginfo_class_RedisCluster_bzpopmax
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_bzmpop, 0, 3, RedisCluster, MAY_BE_ARRAY|MAY_BE_NULL|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, timeout, IS_DOUBLE, 0)
ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO(0, from, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "1")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_zmpop, 0, 2, RedisCluster, MAY_BE_ARRAY|MAY_BE_NULL|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO(0, from, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "1")
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_blmpop arginfo_class_RedisCluster_bzmpop
#define arginfo_class_RedisCluster_lmpop arginfo_class_RedisCluster_zmpop
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_clearlasterror, 0, 0, _IS_BOOL, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_RedisCluster_client, 0, 2, MAY_BE_ARRAY|MAY_BE_STRING|MAY_BE_BOOL)
ZEND_ARG_TYPE_MASK(0, key_or_address, MAY_BE_STRING|MAY_BE_ARRAY, NULL)
ZEND_ARG_TYPE_INFO(0, subcommand, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, arg, IS_STRING, 1, "NULL")
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_close arginfo_class_RedisCluster_clearlasterror
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_cluster, 0, 2, IS_MIXED, 0)
ZEND_ARG_TYPE_MASK(0, key_or_address, MAY_BE_STRING|MAY_BE_ARRAY, NULL)
ZEND_ARG_TYPE_INFO(0, command, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, extra_args, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_command, 0, 0, IS_MIXED, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, extra_args, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_config, 0, 2, IS_MIXED, 0)
ZEND_ARG_TYPE_MASK(0, key_or_address, MAY_BE_STRING|MAY_BE_ARRAY, NULL)
ZEND_ARG_TYPE_INFO(0, subcommand, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, extra_args, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_dbsize, 0, 1, RedisCluster, MAY_BE_LONG)
ZEND_ARG_TYPE_MASK(0, key_or_address, MAY_BE_STRING|MAY_BE_ARRAY, NULL)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_copy, 0, 2, RedisCluster, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, src, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_decr, 0, 1, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, by, IS_LONG, 0, "1")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_decrby, 0, 2, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_decrbyfloat, 0, 2, IS_DOUBLE, 0)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_DOUBLE, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_del, 0, 1, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_MASK(0, key, MAY_BE_ARRAY|MAY_BE_STRING, NULL)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_keys, IS_STRING, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_discard arginfo_class_RedisCluster_clearlasterror
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_dump, 0, 1, RedisCluster, MAY_BE_STRING|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_echo, 0, 2, RedisCluster, MAY_BE_STRING|MAY_BE_FALSE)
ZEND_ARG_TYPE_MASK(0, key_or_address, MAY_BE_STRING|MAY_BE_ARRAY, NULL)
ZEND_ARG_TYPE_INFO(0, msg, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_eval, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, script, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, args, IS_ARRAY, 0, "[]")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, num_keys, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_eval_ro arginfo_class_RedisCluster_eval
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_evalsha, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, script_sha, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, args, IS_ARRAY, 0, "[]")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, num_keys, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_evalsha_ro arginfo_class_RedisCluster_evalsha
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_RedisCluster_exec, 0, 0, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_exists, 0, 1, RedisCluster, MAY_BE_LONG|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_MIXED, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_keys, IS_MIXED, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_touch arginfo_class_RedisCluster_exists
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_expire, 0, 2, RedisCluster, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, timeout, IS_LONG, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_STRING, 1, "NULL")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_expireat, 0, 2, RedisCluster, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, timestamp, IS_LONG, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_STRING, 1, "NULL")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_expiretime, 0, 1, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_pexpiretime arginfo_class_RedisCluster_expiretime
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_flushall, 0, 1, RedisCluster, MAY_BE_BOOL)
ZEND_ARG_TYPE_MASK(0, key_or_address, MAY_BE_STRING|MAY_BE_ARRAY, NULL)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, async, _IS_BOOL, 0, "false")
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_flushdb arginfo_class_RedisCluster_flushall
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_geoadd, 0, 4, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, lng, IS_DOUBLE, 0)
ZEND_ARG_TYPE_INFO(0, lat, IS_DOUBLE, 0)
ZEND_ARG_TYPE_INFO(0, member, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_triples_and_options, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_geodist, 0, 3, RedisCluster, MAY_BE_DOUBLE|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, src, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, dest, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, unit, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_geohash, 0, 2, RedisCluster, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, member, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_members, IS_STRING, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_geopos arginfo_class_RedisCluster_geohash
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_georadius, 0, 5, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, lng, IS_DOUBLE, 0)
ZEND_ARG_TYPE_INFO(0, lat, IS_DOUBLE, 0)
ZEND_ARG_TYPE_INFO(0, radius, IS_DOUBLE, 0)
ZEND_ARG_TYPE_INFO(0, unit, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "[]")
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_georadius_ro arginfo_class_RedisCluster_georadius
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_georadiusbymember, 0, 4, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, member, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, radius, IS_DOUBLE, 0)
ZEND_ARG_TYPE_INFO(0, unit, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "[]")
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_georadiusbymember_ro arginfo_class_RedisCluster_georadiusbymember
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_geosearch, 0, 4, RedisCluster, MAY_BE_ARRAY)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_MASK(0, position, MAY_BE_ARRAY|MAY_BE_STRING, NULL)
ZEND_ARG_TYPE_MASK(0, shape, MAY_BE_ARRAY|MAY_BE_LONG|MAY_BE_DOUBLE, NULL)
ZEND_ARG_TYPE_INFO(0, unit, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "[]")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_geosearchstore, 0, 5, RedisCluster, MAY_BE_ARRAY|MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, src, IS_STRING, 0)
ZEND_ARG_TYPE_MASK(0, position, MAY_BE_ARRAY|MAY_BE_STRING, NULL)
ZEND_ARG_TYPE_MASK(0, shape, MAY_BE_ARRAY|MAY_BE_LONG|MAY_BE_DOUBLE, NULL)
ZEND_ARG_TYPE_INFO(0, unit, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "[]")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_get, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_getbit arginfo_class_RedisCluster_decrby
#define arginfo_class_RedisCluster_getlasterror arginfo_class_RedisCluster__redir
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_getmode, 0, 0, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_getoption, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, option, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_getrange, 0, 3, RedisCluster, MAY_BE_STRING|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, start, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, end, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_lcs, 0, 2, RedisCluster, MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key1, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, key2, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "NULL")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_getset, 0, 2, RedisCluster, MAY_BE_STRING|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_gettransferredbytes arginfo_class_RedisCluster_exec
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_cleartransferredbytes, 0, 0, IS_VOID, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_hdel, 0, 2, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, member, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_members, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_hexists, 0, 2, RedisCluster, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, member, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_hget, 0, 2, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, member, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_hgetall, 0, 1, RedisCluster, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_hincrby, 0, 3, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, member, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_hincrbyfloat, 0, 3, RedisCluster, MAY_BE_DOUBLE|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, member, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_DOUBLE, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_hkeys arginfo_class_RedisCluster_hgetall
#define arginfo_class_RedisCluster_hlen arginfo_class_RedisCluster_expiretime
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_hmget, 0, 2, RedisCluster, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_hmset, 0, 2, RedisCluster, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, key_values, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_RedisCluster_hscan, 0, 2, MAY_BE_ARRAY|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(1, iterator, IS_LONG, 1)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, pattern, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_hrandfield, 0, 1, RedisCluster, MAY_BE_STRING|MAY_BE_ARRAY)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_hset, 0, 3, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, member, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_hsetnx, 0, 3, RedisCluster, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, member, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_hstrlen, 0, 2, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, field, IS_STRING, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_hvals arginfo_class_RedisCluster_hgetall
#define arginfo_class_RedisCluster_incr arginfo_class_RedisCluster_decr
#define arginfo_class_RedisCluster_incrby arginfo_class_RedisCluster_decrby
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_incrbyfloat, 0, 2, RedisCluster, MAY_BE_DOUBLE|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_DOUBLE, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_info, 0, 1, RedisCluster, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_MASK(0, key_or_address, MAY_BE_STRING|MAY_BE_ARRAY, NULL)
ZEND_ARG_VARIADIC_TYPE_INFO(0, sections, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_keys, 0, 1, RedisCluster, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, pattern, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_lastsave, 0, 1, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_MASK(0, key_or_address, MAY_BE_STRING|MAY_BE_ARRAY, NULL)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_lget, 0, 2, RedisCluster, MAY_BE_STRING|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, index, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_lindex, 0, 2, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, index, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_linsert, 0, 4, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, pos, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, pivot, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_llen, 0, 1, RedisCluster, MAY_BE_LONG|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_lpop, 0, 1, RedisCluster, MAY_BE_BOOL|MAY_BE_STRING|MAY_BE_ARRAY)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_lpos, 0, 2, Redis, MAY_BE_NULL|MAY_BE_BOOL|MAY_BE_LONG|MAY_BE_ARRAY)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_lpush, 0, 2, RedisCluster, MAY_BE_LONG|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_values, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_lpushx, 0, 2, RedisCluster, MAY_BE_LONG|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_lrange, 0, 3, RedisCluster, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, start, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, end, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_lrem, 0, 2, RedisCluster, MAY_BE_LONG|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_lset, 0, 3, RedisCluster, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, index, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_ltrim, 0, 3, RedisCluster, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, start, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, end, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_mget, 0, 1, RedisCluster, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_mset, 0, 1, RedisCluster, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key_values, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_msetnx, 0, 1, RedisCluster, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key_values, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_multi, 0, 0, RedisCluster, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, value, IS_LONG, 0, "Redis::MULTI")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_object, 0, 2, RedisCluster, MAY_BE_LONG|MAY_BE_STRING|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, subcommand, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_persist, 0, 1, RedisCluster, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_pexpire arginfo_class_RedisCluster_expire
#define arginfo_class_RedisCluster_pexpireat arginfo_class_RedisCluster_expireat
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_pfadd, 0, 2, RedisCluster, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, elements, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_pfcount arginfo_class_RedisCluster_expiretime
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_pfmerge, 0, 2, RedisCluster, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_ping, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_MASK(0, key_or_address, MAY_BE_STRING|MAY_BE_ARRAY, NULL)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, message, IS_STRING, 1, "NULL")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_psetex, 0, 3, RedisCluster, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, timeout, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_psubscribe, 0, 2, IS_VOID, 0)
ZEND_ARG_TYPE_INFO(0, patterns, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_pttl arginfo_class_RedisCluster_expiretime
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_publish, 0, 2, RedisCluster, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, channel, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, message, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_pubsub, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_MASK(0, key_or_address, MAY_BE_STRING|MAY_BE_ARRAY, NULL)
ZEND_ARG_VARIADIC_TYPE_INFO(0, values, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_RedisCluster_punsubscribe, 0, 1, MAY_BE_BOOL|MAY_BE_ARRAY)
ZEND_ARG_TYPE_INFO(0, pattern, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_patterns, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_randomkey, 0, 1, RedisCluster, MAY_BE_BOOL|MAY_BE_STRING)
ZEND_ARG_TYPE_MASK(0, key_or_address, MAY_BE_STRING|MAY_BE_ARRAY, NULL)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_rawcommand, 0, 2, IS_MIXED, 0)
ZEND_ARG_TYPE_MASK(0, key_or_address, MAY_BE_STRING|MAY_BE_ARRAY, NULL)
ZEND_ARG_TYPE_INFO(0, command, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, args, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_rename, 0, 2, RedisCluster, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key_src, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, key_dst, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_renamenx, 0, 2, RedisCluster, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, newkey, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_restore, 0, 3, RedisCluster, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, timeout, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "NULL")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_role, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_MASK(0, key_or_address, MAY_BE_STRING|MAY_BE_ARRAY, NULL)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_rpop arginfo_class_RedisCluster_lpop
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_rpoplpush, 0, 2, RedisCluster, MAY_BE_BOOL|MAY_BE_STRING)
ZEND_ARG_TYPE_INFO(0, src, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_rpush, 0, 1, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, elements, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_rpushx, 0, 2, RedisCluster, MAY_BE_BOOL|MAY_BE_LONG)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_sadd, 0, 2, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_values, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_saddarray, 0, 2, RedisCluster, MAY_BE_BOOL|MAY_BE_LONG)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, values, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_save arginfo_class_RedisCluster_bgrewriteaof
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_RedisCluster_scan, 0, 2, MAY_BE_BOOL|MAY_BE_ARRAY)
ZEND_ARG_TYPE_INFO(1, iterator, IS_LONG, 1)
ZEND_ARG_TYPE_MASK(0, key_or_address, MAY_BE_STRING|MAY_BE_ARRAY, NULL)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, pattern, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_scard arginfo_class_RedisCluster_expiretime
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_script, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_MASK(0, key_or_address, MAY_BE_STRING|MAY_BE_ARRAY, NULL)
ZEND_ARG_VARIADIC_TYPE_INFO(0, args, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_sdiff, 0, 1, RedisCluster, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_keys, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_sdiffstore, 0, 2, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_keys, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_set, 0, 2, RedisCluster, MAY_BE_STRING|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_MIXED, 0, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_setbit, 0, 3, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, offset, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, onoff, _IS_BOOL, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_setex, 0, 3, RedisCluster, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, expire, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_setnx, 0, 2, RedisCluster, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_setoption, 0, 2, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO(0, option, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_setrange, 0, 3, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, offset, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_sinter, 0, 1, RedisCluster, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_MASK(0, key, MAY_BE_ARRAY|MAY_BE_STRING, NULL)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_keys, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_sintercard, 0, 1, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, limit, IS_LONG, 0, "-1")
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_sinterstore arginfo_class_RedisCluster_del
#define arginfo_class_RedisCluster_sismember arginfo_class_RedisCluster_setnx
#define arginfo_class_RedisCluster_smismember arginfo_class_RedisCluster_geohash
#define arginfo_class_RedisCluster_slowlog arginfo_class_RedisCluster_script
#define arginfo_class_RedisCluster_smembers arginfo_class_RedisCluster_hgetall
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_smove, 0, 3, RedisCluster, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, src, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, member, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_sort, 0, 1, RedisCluster, MAY_BE_ARRAY|MAY_BE_BOOL|MAY_BE_LONG|MAY_BE_STRING)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "NULL")
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_sort_ro arginfo_class_RedisCluster_sort
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_spop, 0, 1, RedisCluster, MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_srandmember arginfo_class_RedisCluster_spop
#define arginfo_class_RedisCluster_srem arginfo_class_RedisCluster_sadd
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_RedisCluster_sscan, 0, 2, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(1, iterator, IS_LONG, 1)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, pattern, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_strlen arginfo_class_RedisCluster_expiretime
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_subscribe, 0, 2, IS_VOID, 0)
ZEND_ARG_TYPE_INFO(0, channels, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO(0, cb, IS_CALLABLE, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_sunion, 0, 1, RedisCluster, MAY_BE_BOOL|MAY_BE_ARRAY)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_keys, IS_STRING, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_sunionstore arginfo_class_RedisCluster_sdiffstore
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_time, 0, 1, RedisCluster, MAY_BE_BOOL|MAY_BE_ARRAY)
ZEND_ARG_TYPE_MASK(0, key_or_address, MAY_BE_STRING|MAY_BE_ARRAY, NULL)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_ttl arginfo_class_RedisCluster_expiretime
#define arginfo_class_RedisCluster_type arginfo_class_RedisCluster_expiretime
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_RedisCluster_unsubscribe, 0, 1, MAY_BE_BOOL|MAY_BE_ARRAY)
ZEND_ARG_TYPE_INFO(0, channels, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_unlink arginfo_class_RedisCluster_del
#define arginfo_class_RedisCluster_unwatch arginfo_class_RedisCluster_clearlasterror
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_watch, 0, 1, RedisCluster, MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_keys, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_xack, 0, 3, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, group, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, ids, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_xadd, 0, 3, RedisCluster, MAY_BE_STRING|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, id, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, values, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, maxlen, IS_LONG, 0, "0")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, approx, _IS_BOOL, 0, "false")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_xclaim, 0, 6, RedisCluster, MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, group, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, consumer, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, min_iddle, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, ids, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO(0, options, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_xdel, 0, 2, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, ids, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_xgroup, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, operation, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, key, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, group, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, id_or_consumer, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mkstream, _IS_BOOL, 0, "false")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, entries_read, IS_LONG, 0, "-2")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_xautoclaim, 0, 5, RedisCluster, MAY_BE_BOOL|MAY_BE_ARRAY)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, group, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, consumer, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, min_idle, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, start, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "-1")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, justid, _IS_BOOL, 0, "false")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_xinfo, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, operation, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, arg1, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, arg2, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "-1")
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_xlen arginfo_class_RedisCluster_expiretime
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_xpending, 0, 2, RedisCluster, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, group, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, start, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, end, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "-1")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, consumer, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_xrange, 0, 3, RedisCluster, MAY_BE_BOOL|MAY_BE_ARRAY)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, start, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, end, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "-1")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_xread, 0, 1, RedisCluster, MAY_BE_BOOL|MAY_BE_ARRAY)
ZEND_ARG_TYPE_INFO(0, streams, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "-1")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, block, IS_LONG, 0, "-1")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_xreadgroup, 0, 3, RedisCluster, MAY_BE_BOOL|MAY_BE_ARRAY)
ZEND_ARG_TYPE_INFO(0, group, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, consumer, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, streams, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "1")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, block, IS_LONG, 0, "1")
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_xrevrange arginfo_class_RedisCluster_xrange
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_xtrim, 0, 2, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, maxlen, IS_LONG, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, approx, _IS_BOOL, 0, "false")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, minid, _IS_BOOL, 0, "false")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, limit, IS_LONG, 0, "-1")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_zadd, 0, 2, RedisCluster, MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_MASK(0, score_or_options, MAY_BE_ARRAY|MAY_BE_DOUBLE, NULL)
ZEND_ARG_VARIADIC_TYPE_INFO(0, more_scores_and_mems, IS_MIXED, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_zcard arginfo_class_RedisCluster_expiretime
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_zcount, 0, 3, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, start, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, end, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_zincrby, 0, 3, RedisCluster, MAY_BE_DOUBLE|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_DOUBLE, 0)
ZEND_ARG_TYPE_INFO(0, member, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_zinterstore, 0, 2, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, weights, IS_ARRAY, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, aggregate, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_zintercard arginfo_class_RedisCluster_sintercard
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_zlexcount, 0, 3, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, min, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, max, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_zpopmax, 0, 1, RedisCluster, MAY_BE_BOOL|MAY_BE_ARRAY)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, value, IS_LONG, 1, "null")
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_zpopmin arginfo_class_RedisCluster_zpopmax
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_zrange, 0, 3, RedisCluster, MAY_BE_ARRAY|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, start, IS_MIXED, 0)
ZEND_ARG_TYPE_INFO(0, end, IS_MIXED, 0)
ZEND_ARG_TYPE_MASK(0, options, MAY_BE_ARRAY|MAY_BE_BOOL|MAY_BE_NULL, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_zrangestore, 0, 4, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, dstkey, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, srckey, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, start, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, end, IS_LONG, 0)
ZEND_ARG_TYPE_MASK(0, options, MAY_BE_ARRAY|MAY_BE_BOOL|MAY_BE_NULL, "null")
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_zrandmember arginfo_class_RedisCluster_hrandfield
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_zrangebylex, 0, 3, RedisCluster, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, min, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, max, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, offset, IS_LONG, 0, "-1")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "-1")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_zrangebyscore, 0, 3, RedisCluster, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, start, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, end, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "[]")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_zrank, 0, 2, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, member, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_zrem, 0, 2, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_values, IS_STRING, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_zremrangebylex arginfo_class_RedisCluster_zlexcount
#define arginfo_class_RedisCluster_zremrangebyrank arginfo_class_RedisCluster_zlexcount
#define arginfo_class_RedisCluster_zremrangebyscore arginfo_class_RedisCluster_zlexcount
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_zrevrange, 0, 3, RedisCluster, MAY_BE_BOOL|MAY_BE_ARRAY)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, min, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, max, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null")
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_zrevrangebylex arginfo_class_RedisCluster_zrevrange
#define arginfo_class_RedisCluster_zrevrangebyscore arginfo_class_RedisCluster_zrevrange
#define arginfo_class_RedisCluster_zrevrank arginfo_class_RedisCluster_zrank
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_zscan, 0, 2, RedisCluster, MAY_BE_BOOL|MAY_BE_ARRAY)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(1, iterator, IS_LONG, 1)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, pattern, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_zscore, 0, 2, RedisCluster, MAY_BE_DOUBLE|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, member, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_zmscore, 0, 2, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, member, IS_MIXED, 0)
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_members, IS_MIXED, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_zunionstore, 0, 2, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, weights, IS_ARRAY, 1, "NULL")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, aggregate, IS_STRING, 1, "NULL")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_zinter, 0, 1, RedisCluster, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, weights, IS_ARRAY, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_zdiffstore, 0, 2, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_zunion arginfo_class_RedisCluster_zinter
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_zdiff, 0, 1, RedisCluster, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, keys, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null")
ZEND_END_ARG_INFO()
ZEND_METHOD(RedisCluster, __construct);
ZEND_METHOD(RedisCluster, _compress);
ZEND_METHOD(RedisCluster, _uncompress);
ZEND_METHOD(RedisCluster, _serialize);
ZEND_METHOD(RedisCluster, _unserialize);
ZEND_METHOD(RedisCluster, _pack);
ZEND_METHOD(RedisCluster, _unpack);
ZEND_METHOD(RedisCluster, _prefix);
ZEND_METHOD(RedisCluster, _masters);
ZEND_METHOD(RedisCluster, _redir);
ZEND_METHOD(RedisCluster, acl);
ZEND_METHOD(RedisCluster, append);
ZEND_METHOD(RedisCluster, bgrewriteaof);
ZEND_METHOD(RedisCluster, bgsave);
ZEND_METHOD(RedisCluster, bitcount);
ZEND_METHOD(RedisCluster, bitop);
ZEND_METHOD(RedisCluster, bitpos);
ZEND_METHOD(RedisCluster, blpop);
ZEND_METHOD(RedisCluster, brpop);
ZEND_METHOD(RedisCluster, brpoplpush);
ZEND_METHOD(RedisCluster, lmove);
ZEND_METHOD(RedisCluster, blmove);
ZEND_METHOD(RedisCluster, bzpopmax);
ZEND_METHOD(RedisCluster, bzpopmin);
ZEND_METHOD(RedisCluster, bzmpop);
ZEND_METHOD(RedisCluster, zmpop);
ZEND_METHOD(RedisCluster, blmpop);
ZEND_METHOD(RedisCluster, lmpop);
ZEND_METHOD(RedisCluster, clearlasterror);
ZEND_METHOD(RedisCluster, client);
ZEND_METHOD(RedisCluster, close);
ZEND_METHOD(RedisCluster, cluster);
ZEND_METHOD(RedisCluster, command);
ZEND_METHOD(RedisCluster, config);
ZEND_METHOD(RedisCluster, dbsize);
ZEND_METHOD(RedisCluster, copy);
ZEND_METHOD(RedisCluster, decr);
ZEND_METHOD(RedisCluster, decrby);
ZEND_METHOD(RedisCluster, decrbyfloat);
ZEND_METHOD(RedisCluster, del);
ZEND_METHOD(RedisCluster, discard);
ZEND_METHOD(RedisCluster, dump);
ZEND_METHOD(RedisCluster, echo);
ZEND_METHOD(RedisCluster, eval);
ZEND_METHOD(RedisCluster, eval_ro);
ZEND_METHOD(RedisCluster, evalsha);
ZEND_METHOD(RedisCluster, evalsha_ro);
ZEND_METHOD(RedisCluster, exec);
ZEND_METHOD(RedisCluster, exists);
ZEND_METHOD(RedisCluster, touch);
ZEND_METHOD(RedisCluster, expire);
ZEND_METHOD(RedisCluster, expireat);
ZEND_METHOD(RedisCluster, expiretime);
ZEND_METHOD(RedisCluster, pexpiretime);
ZEND_METHOD(RedisCluster, flushall);
ZEND_METHOD(RedisCluster, flushdb);
ZEND_METHOD(RedisCluster, geoadd);
ZEND_METHOD(RedisCluster, geodist);
ZEND_METHOD(RedisCluster, geohash);
ZEND_METHOD(RedisCluster, geopos);
ZEND_METHOD(RedisCluster, georadius);
ZEND_METHOD(RedisCluster, georadius_ro);
ZEND_METHOD(RedisCluster, georadiusbymember);
ZEND_METHOD(RedisCluster, georadiusbymember_ro);
ZEND_METHOD(RedisCluster, geosearch);
ZEND_METHOD(RedisCluster, geosearchstore);
ZEND_METHOD(RedisCluster, get);
ZEND_METHOD(RedisCluster, getbit);
ZEND_METHOD(RedisCluster, getlasterror);
ZEND_METHOD(RedisCluster, getmode);
ZEND_METHOD(RedisCluster, getoption);
ZEND_METHOD(RedisCluster, getrange);
ZEND_METHOD(RedisCluster, lcs);
ZEND_METHOD(RedisCluster, getset);
ZEND_METHOD(RedisCluster, gettransferredbytes);
ZEND_METHOD(RedisCluster, cleartransferredbytes);
ZEND_METHOD(RedisCluster, hdel);
ZEND_METHOD(RedisCluster, hexists);
ZEND_METHOD(RedisCluster, hget);
ZEND_METHOD(RedisCluster, hgetall);
ZEND_METHOD(RedisCluster, hincrby);
ZEND_METHOD(RedisCluster, hincrbyfloat);
ZEND_METHOD(RedisCluster, hkeys);
ZEND_METHOD(RedisCluster, hlen);
ZEND_METHOD(RedisCluster, hmget);
ZEND_METHOD(RedisCluster, hmset);
ZEND_METHOD(RedisCluster, hscan);
ZEND_METHOD(RedisCluster, hrandfield);
ZEND_METHOD(RedisCluster, hset);
ZEND_METHOD(RedisCluster, hsetnx);
ZEND_METHOD(RedisCluster, hstrlen);
ZEND_METHOD(RedisCluster, hvals);
ZEND_METHOD(RedisCluster, incr);
ZEND_METHOD(RedisCluster, incrby);
ZEND_METHOD(RedisCluster, incrbyfloat);
ZEND_METHOD(RedisCluster, info);
ZEND_METHOD(RedisCluster, keys);
ZEND_METHOD(RedisCluster, lastsave);
ZEND_METHOD(RedisCluster, lget);
ZEND_METHOD(RedisCluster, lindex);
ZEND_METHOD(RedisCluster, linsert);
ZEND_METHOD(RedisCluster, llen);
ZEND_METHOD(RedisCluster, lpop);
ZEND_METHOD(RedisCluster, lpos);
ZEND_METHOD(RedisCluster, lpush);
ZEND_METHOD(RedisCluster, lpushx);
ZEND_METHOD(RedisCluster, lrange);
ZEND_METHOD(RedisCluster, lrem);
ZEND_METHOD(RedisCluster, lset);
ZEND_METHOD(RedisCluster, ltrim);
ZEND_METHOD(RedisCluster, mget);
ZEND_METHOD(RedisCluster, mset);
ZEND_METHOD(RedisCluster, msetnx);
ZEND_METHOD(RedisCluster, multi);
ZEND_METHOD(RedisCluster, object);
ZEND_METHOD(RedisCluster, persist);
ZEND_METHOD(RedisCluster, pexpire);
ZEND_METHOD(RedisCluster, pexpireat);
ZEND_METHOD(RedisCluster, pfadd);
ZEND_METHOD(RedisCluster, pfcount);
ZEND_METHOD(RedisCluster, pfmerge);
ZEND_METHOD(RedisCluster, ping);
ZEND_METHOD(RedisCluster, psetex);
ZEND_METHOD(RedisCluster, psubscribe);
ZEND_METHOD(RedisCluster, pttl);
ZEND_METHOD(RedisCluster, publish);
ZEND_METHOD(RedisCluster, pubsub);
ZEND_METHOD(RedisCluster, punsubscribe);
ZEND_METHOD(RedisCluster, randomkey);
ZEND_METHOD(RedisCluster, rawcommand);
ZEND_METHOD(RedisCluster, rename);
ZEND_METHOD(RedisCluster, renamenx);
ZEND_METHOD(RedisCluster, restore);
ZEND_METHOD(RedisCluster, role);
ZEND_METHOD(RedisCluster, rpop);
ZEND_METHOD(RedisCluster, rpoplpush);
ZEND_METHOD(RedisCluster, rpush);
ZEND_METHOD(RedisCluster, rpushx);
ZEND_METHOD(RedisCluster, sadd);
ZEND_METHOD(RedisCluster, saddarray);
ZEND_METHOD(RedisCluster, save);
ZEND_METHOD(RedisCluster, scan);
ZEND_METHOD(RedisCluster, scard);
ZEND_METHOD(RedisCluster, script);
ZEND_METHOD(RedisCluster, sdiff);
ZEND_METHOD(RedisCluster, sdiffstore);
ZEND_METHOD(RedisCluster, set);
ZEND_METHOD(RedisCluster, setbit);
ZEND_METHOD(RedisCluster, setex);
ZEND_METHOD(RedisCluster, setnx);
ZEND_METHOD(RedisCluster, setoption);
ZEND_METHOD(RedisCluster, setrange);
ZEND_METHOD(RedisCluster, sinter);
ZEND_METHOD(RedisCluster, sintercard);
ZEND_METHOD(RedisCluster, sinterstore);
ZEND_METHOD(RedisCluster, sismember);
ZEND_METHOD(RedisCluster, smismember);
ZEND_METHOD(RedisCluster, slowlog);
ZEND_METHOD(RedisCluster, smembers);
ZEND_METHOD(RedisCluster, smove);
ZEND_METHOD(RedisCluster, sort);
ZEND_METHOD(RedisCluster, sort_ro);
ZEND_METHOD(RedisCluster, spop);
ZEND_METHOD(RedisCluster, srandmember);
ZEND_METHOD(RedisCluster, srem);
ZEND_METHOD(RedisCluster, sscan);
ZEND_METHOD(RedisCluster, strlen);
ZEND_METHOD(RedisCluster, subscribe);
ZEND_METHOD(RedisCluster, sunion);
ZEND_METHOD(RedisCluster, sunionstore);
ZEND_METHOD(RedisCluster, time);
ZEND_METHOD(RedisCluster, ttl);
ZEND_METHOD(RedisCluster, type);
ZEND_METHOD(RedisCluster, unsubscribe);
ZEND_METHOD(RedisCluster, unlink);
ZEND_METHOD(RedisCluster, unwatch);
ZEND_METHOD(RedisCluster, watch);
ZEND_METHOD(RedisCluster, xack);
ZEND_METHOD(RedisCluster, xadd);
ZEND_METHOD(RedisCluster, xclaim);
ZEND_METHOD(RedisCluster, xdel);
ZEND_METHOD(RedisCluster, xgroup);
ZEND_METHOD(RedisCluster, xautoclaim);
ZEND_METHOD(RedisCluster, xinfo);
ZEND_METHOD(RedisCluster, xlen);
ZEND_METHOD(RedisCluster, xpending);
ZEND_METHOD(RedisCluster, xrange);
ZEND_METHOD(RedisCluster, xread);
ZEND_METHOD(RedisCluster, xreadgroup);
ZEND_METHOD(RedisCluster, xrevrange);
ZEND_METHOD(RedisCluster, xtrim);
ZEND_METHOD(RedisCluster, zadd);
ZEND_METHOD(RedisCluster, zcard);
ZEND_METHOD(RedisCluster, zcount);
ZEND_METHOD(RedisCluster, zincrby);
ZEND_METHOD(RedisCluster, zinterstore);
ZEND_METHOD(RedisCluster, zintercard);
ZEND_METHOD(RedisCluster, zlexcount);
ZEND_METHOD(RedisCluster, zpopmax);
ZEND_METHOD(RedisCluster, zpopmin);
ZEND_METHOD(RedisCluster, zrange);
ZEND_METHOD(RedisCluster, zrangestore);
ZEND_METHOD(RedisCluster, zrandmember);
ZEND_METHOD(RedisCluster, zrangebylex);
ZEND_METHOD(RedisCluster, zrangebyscore);
ZEND_METHOD(RedisCluster, zrank);
ZEND_METHOD(RedisCluster, zrem);
ZEND_METHOD(RedisCluster, zremrangebylex);
ZEND_METHOD(RedisCluster, zremrangebyrank);
ZEND_METHOD(RedisCluster, zremrangebyscore);
ZEND_METHOD(RedisCluster, zrevrange);
ZEND_METHOD(RedisCluster, zrevrangebylex);
ZEND_METHOD(RedisCluster, zrevrangebyscore);
ZEND_METHOD(RedisCluster, zrevrank);
ZEND_METHOD(RedisCluster, zscan);
ZEND_METHOD(RedisCluster, zscore);
ZEND_METHOD(RedisCluster, zmscore);
ZEND_METHOD(RedisCluster, zunionstore);
ZEND_METHOD(RedisCluster, zinter);
ZEND_METHOD(RedisCluster, zdiffstore);
ZEND_METHOD(RedisCluster, zunion);
ZEND_METHOD(RedisCluster, zdiff);
static const zend_function_entry class_RedisCluster_methods[] = {
ZEND_ME(RedisCluster, __construct, arginfo_class_RedisCluster___construct, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, _compress, arginfo_class_RedisCluster__compress, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, _uncompress, arginfo_class_RedisCluster__uncompress, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, _serialize, arginfo_class_RedisCluster__serialize, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, _unserialize, arginfo_class_RedisCluster__unserialize, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, _pack, arginfo_class_RedisCluster__pack, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, _unpack, arginfo_class_RedisCluster__unpack, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, _prefix, arginfo_class_RedisCluster__prefix, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, _masters, arginfo_class_RedisCluster__masters, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, _redir, arginfo_class_RedisCluster__redir, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, acl, arginfo_class_RedisCluster_acl, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, append, arginfo_class_RedisCluster_append, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, bgrewriteaof, arginfo_class_RedisCluster_bgrewriteaof, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, bgsave, arginfo_class_RedisCluster_bgsave, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, bitcount, arginfo_class_RedisCluster_bitcount, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, bitop, arginfo_class_RedisCluster_bitop, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, bitpos, arginfo_class_RedisCluster_bitpos, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, blpop, arginfo_class_RedisCluster_blpop, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, brpop, arginfo_class_RedisCluster_brpop, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, brpoplpush, arginfo_class_RedisCluster_brpoplpush, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lmove, arginfo_class_RedisCluster_lmove, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, blmove, arginfo_class_RedisCluster_blmove, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, bzpopmax, arginfo_class_RedisCluster_bzpopmax, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, bzpopmin, arginfo_class_RedisCluster_bzpopmin, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, bzmpop, arginfo_class_RedisCluster_bzmpop, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zmpop, arginfo_class_RedisCluster_zmpop, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, blmpop, arginfo_class_RedisCluster_blmpop, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lmpop, arginfo_class_RedisCluster_lmpop, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, clearlasterror, arginfo_class_RedisCluster_clearlasterror, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, client, arginfo_class_RedisCluster_client, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, close, arginfo_class_RedisCluster_close, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, cluster, arginfo_class_RedisCluster_cluster, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, command, arginfo_class_RedisCluster_command, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, config, arginfo_class_RedisCluster_config, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, dbsize, arginfo_class_RedisCluster_dbsize, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, copy, arginfo_class_RedisCluster_copy, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, decr, arginfo_class_RedisCluster_decr, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, decrby, arginfo_class_RedisCluster_decrby, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, decrbyfloat, arginfo_class_RedisCluster_decrbyfloat, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, del, arginfo_class_RedisCluster_del, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, discard, arginfo_class_RedisCluster_discard, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, dump, arginfo_class_RedisCluster_dump, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, echo, arginfo_class_RedisCluster_echo, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, eval, arginfo_class_RedisCluster_eval, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, eval_ro, arginfo_class_RedisCluster_eval_ro, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, evalsha, arginfo_class_RedisCluster_evalsha, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, evalsha_ro, arginfo_class_RedisCluster_evalsha_ro, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, exec, arginfo_class_RedisCluster_exec, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, exists, arginfo_class_RedisCluster_exists, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, touch, arginfo_class_RedisCluster_touch, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, expire, arginfo_class_RedisCluster_expire, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, expireat, arginfo_class_RedisCluster_expireat, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, expiretime, arginfo_class_RedisCluster_expiretime, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, pexpiretime, arginfo_class_RedisCluster_pexpiretime, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, flushall, arginfo_class_RedisCluster_flushall, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, flushdb, arginfo_class_RedisCluster_flushdb, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, geoadd, arginfo_class_RedisCluster_geoadd, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, geodist, arginfo_class_RedisCluster_geodist, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, geohash, arginfo_class_RedisCluster_geohash, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, geopos, arginfo_class_RedisCluster_geopos, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, georadius, arginfo_class_RedisCluster_georadius, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, georadius_ro, arginfo_class_RedisCluster_georadius_ro, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, georadiusbymember, arginfo_class_RedisCluster_georadiusbymember, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, georadiusbymember_ro, arginfo_class_RedisCluster_georadiusbymember_ro, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, geosearch, arginfo_class_RedisCluster_geosearch, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, geosearchstore, arginfo_class_RedisCluster_geosearchstore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, get, arginfo_class_RedisCluster_get, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, getbit, arginfo_class_RedisCluster_getbit, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, getlasterror, arginfo_class_RedisCluster_getlasterror, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, getmode, arginfo_class_RedisCluster_getmode, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, getoption, arginfo_class_RedisCluster_getoption, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, getrange, arginfo_class_RedisCluster_getrange, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lcs, arginfo_class_RedisCluster_lcs, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, getset, arginfo_class_RedisCluster_getset, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, gettransferredbytes, arginfo_class_RedisCluster_gettransferredbytes, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, cleartransferredbytes, arginfo_class_RedisCluster_cleartransferredbytes, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hdel, arginfo_class_RedisCluster_hdel, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hexists, arginfo_class_RedisCluster_hexists, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hget, arginfo_class_RedisCluster_hget, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hgetall, arginfo_class_RedisCluster_hgetall, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hincrby, arginfo_class_RedisCluster_hincrby, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hincrbyfloat, arginfo_class_RedisCluster_hincrbyfloat, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hkeys, arginfo_class_RedisCluster_hkeys, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hlen, arginfo_class_RedisCluster_hlen, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hmget, arginfo_class_RedisCluster_hmget, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hmset, arginfo_class_RedisCluster_hmset, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hscan, arginfo_class_RedisCluster_hscan, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hrandfield, arginfo_class_RedisCluster_hrandfield, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hset, arginfo_class_RedisCluster_hset, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hsetnx, arginfo_class_RedisCluster_hsetnx, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hstrlen, arginfo_class_RedisCluster_hstrlen, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hvals, arginfo_class_RedisCluster_hvals, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, incr, arginfo_class_RedisCluster_incr, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, incrby, arginfo_class_RedisCluster_incrby, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, incrbyfloat, arginfo_class_RedisCluster_incrbyfloat, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, info, arginfo_class_RedisCluster_info, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, keys, arginfo_class_RedisCluster_keys, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lastsave, arginfo_class_RedisCluster_lastsave, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lget, arginfo_class_RedisCluster_lget, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lindex, arginfo_class_RedisCluster_lindex, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, linsert, arginfo_class_RedisCluster_linsert, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, llen, arginfo_class_RedisCluster_llen, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lpop, arginfo_class_RedisCluster_lpop, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lpos, arginfo_class_RedisCluster_lpos, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lpush, arginfo_class_RedisCluster_lpush, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lpushx, arginfo_class_RedisCluster_lpushx, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lrange, arginfo_class_RedisCluster_lrange, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lrem, arginfo_class_RedisCluster_lrem, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lset, arginfo_class_RedisCluster_lset, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, ltrim, arginfo_class_RedisCluster_ltrim, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, mget, arginfo_class_RedisCluster_mget, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, mset, arginfo_class_RedisCluster_mset, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, msetnx, arginfo_class_RedisCluster_msetnx, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, multi, arginfo_class_RedisCluster_multi, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, object, arginfo_class_RedisCluster_object, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, persist, arginfo_class_RedisCluster_persist, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, pexpire, arginfo_class_RedisCluster_pexpire, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, pexpireat, arginfo_class_RedisCluster_pexpireat, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, pfadd, arginfo_class_RedisCluster_pfadd, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, pfcount, arginfo_class_RedisCluster_pfcount, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, pfmerge, arginfo_class_RedisCluster_pfmerge, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, ping, arginfo_class_RedisCluster_ping, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, psetex, arginfo_class_RedisCluster_psetex, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, psubscribe, arginfo_class_RedisCluster_psubscribe, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, pttl, arginfo_class_RedisCluster_pttl, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, publish, arginfo_class_RedisCluster_publish, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, pubsub, arginfo_class_RedisCluster_pubsub, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, punsubscribe, arginfo_class_RedisCluster_punsubscribe, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, randomkey, arginfo_class_RedisCluster_randomkey, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, rawcommand, arginfo_class_RedisCluster_rawcommand, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, rename, arginfo_class_RedisCluster_rename, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, renamenx, arginfo_class_RedisCluster_renamenx, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, restore, arginfo_class_RedisCluster_restore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, role, arginfo_class_RedisCluster_role, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, rpop, arginfo_class_RedisCluster_rpop, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, rpoplpush, arginfo_class_RedisCluster_rpoplpush, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, rpush, arginfo_class_RedisCluster_rpush, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, rpushx, arginfo_class_RedisCluster_rpushx, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, sadd, arginfo_class_RedisCluster_sadd, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, saddarray, arginfo_class_RedisCluster_saddarray, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, save, arginfo_class_RedisCluster_save, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, scan, arginfo_class_RedisCluster_scan, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, scard, arginfo_class_RedisCluster_scard, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, script, arginfo_class_RedisCluster_script, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, sdiff, arginfo_class_RedisCluster_sdiff, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, sdiffstore, arginfo_class_RedisCluster_sdiffstore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, set, arginfo_class_RedisCluster_set, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, setbit, arginfo_class_RedisCluster_setbit, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, setex, arginfo_class_RedisCluster_setex, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, setnx, arginfo_class_RedisCluster_setnx, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, setoption, arginfo_class_RedisCluster_setoption, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, setrange, arginfo_class_RedisCluster_setrange, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, sinter, arginfo_class_RedisCluster_sinter, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, sintercard, arginfo_class_RedisCluster_sintercard, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, sinterstore, arginfo_class_RedisCluster_sinterstore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, sismember, arginfo_class_RedisCluster_sismember, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, smismember, arginfo_class_RedisCluster_smismember, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, slowlog, arginfo_class_RedisCluster_slowlog, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, smembers, arginfo_class_RedisCluster_smembers, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, smove, arginfo_class_RedisCluster_smove, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, sort, arginfo_class_RedisCluster_sort, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, sort_ro, arginfo_class_RedisCluster_sort_ro, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, spop, arginfo_class_RedisCluster_spop, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, srandmember, arginfo_class_RedisCluster_srandmember, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, srem, arginfo_class_RedisCluster_srem, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, sscan, arginfo_class_RedisCluster_sscan, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, strlen, arginfo_class_RedisCluster_strlen, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, subscribe, arginfo_class_RedisCluster_subscribe, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, sunion, arginfo_class_RedisCluster_sunion, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, sunionstore, arginfo_class_RedisCluster_sunionstore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, time, arginfo_class_RedisCluster_time, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, ttl, arginfo_class_RedisCluster_ttl, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, type, arginfo_class_RedisCluster_type, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, unsubscribe, arginfo_class_RedisCluster_unsubscribe, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, unlink, arginfo_class_RedisCluster_unlink, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, unwatch, arginfo_class_RedisCluster_unwatch, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, watch, arginfo_class_RedisCluster_watch, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xack, arginfo_class_RedisCluster_xack, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xadd, arginfo_class_RedisCluster_xadd, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xclaim, arginfo_class_RedisCluster_xclaim, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xdel, arginfo_class_RedisCluster_xdel, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xgroup, arginfo_class_RedisCluster_xgroup, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xautoclaim, arginfo_class_RedisCluster_xautoclaim, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xinfo, arginfo_class_RedisCluster_xinfo, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xlen, arginfo_class_RedisCluster_xlen, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xpending, arginfo_class_RedisCluster_xpending, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xrange, arginfo_class_RedisCluster_xrange, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xread, arginfo_class_RedisCluster_xread, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xreadgroup, arginfo_class_RedisCluster_xreadgroup, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xrevrange, arginfo_class_RedisCluster_xrevrange, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xtrim, arginfo_class_RedisCluster_xtrim, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zadd, arginfo_class_RedisCluster_zadd, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zcard, arginfo_class_RedisCluster_zcard, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zcount, arginfo_class_RedisCluster_zcount, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zincrby, arginfo_class_RedisCluster_zincrby, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zinterstore, arginfo_class_RedisCluster_zinterstore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zintercard, arginfo_class_RedisCluster_zintercard, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zlexcount, arginfo_class_RedisCluster_zlexcount, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zpopmax, arginfo_class_RedisCluster_zpopmax, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zpopmin, arginfo_class_RedisCluster_zpopmin, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrange, arginfo_class_RedisCluster_zrange, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrangestore, arginfo_class_RedisCluster_zrangestore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrandmember, arginfo_class_RedisCluster_zrandmember, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrangebylex, arginfo_class_RedisCluster_zrangebylex, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrangebyscore, arginfo_class_RedisCluster_zrangebyscore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrank, arginfo_class_RedisCluster_zrank, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrem, arginfo_class_RedisCluster_zrem, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zremrangebylex, arginfo_class_RedisCluster_zremrangebylex, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zremrangebyrank, arginfo_class_RedisCluster_zremrangebyrank, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zremrangebyscore, arginfo_class_RedisCluster_zremrangebyscore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrevrange, arginfo_class_RedisCluster_zrevrange, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrevrangebylex, arginfo_class_RedisCluster_zrevrangebylex, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrevrangebyscore, arginfo_class_RedisCluster_zrevrangebyscore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrevrank, arginfo_class_RedisCluster_zrevrank, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zscan, arginfo_class_RedisCluster_zscan, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zscore, arginfo_class_RedisCluster_zscore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zmscore, arginfo_class_RedisCluster_zmscore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zunionstore, arginfo_class_RedisCluster_zunionstore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zinter, arginfo_class_RedisCluster_zinter, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zdiffstore, arginfo_class_RedisCluster_zdiffstore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zunion, arginfo_class_RedisCluster_zunion, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zdiff, arginfo_class_RedisCluster_zdiff, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
static const zend_function_entry class_RedisClusterException_methods[] = {
ZEND_FE_END
};
static zend_class_entry *register_class_RedisCluster(void)
{
zend_class_entry ce, *class_entry;
INIT_CLASS_ENTRY(ce, "RedisCluster", class_RedisCluster_methods);
class_entry = zend_register_internal_class_ex(&ce, NULL);
zval const_OPT_SLAVE_FAILOVER_value;
ZVAL_LONG(&const_OPT_SLAVE_FAILOVER_value, REDIS_OPT_FAILOVER);
zend_string *const_OPT_SLAVE_FAILOVER_name = zend_string_init_interned("OPT_SLAVE_FAILOVER", sizeof("OPT_SLAVE_FAILOVER") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_SLAVE_FAILOVER_name, &const_OPT_SLAVE_FAILOVER_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_SLAVE_FAILOVER_name);
zval const_FAILOVER_NONE_value;
ZVAL_LONG(&const_FAILOVER_NONE_value, REDIS_FAILOVER_NONE);
zend_string *const_FAILOVER_NONE_name = zend_string_init_interned("FAILOVER_NONE", sizeof("FAILOVER_NONE") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_FAILOVER_NONE_name, &const_FAILOVER_NONE_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_FAILOVER_NONE_name);
zval const_FAILOVER_ERROR_value;
ZVAL_LONG(&const_FAILOVER_ERROR_value, REDIS_FAILOVER_ERROR);
zend_string *const_FAILOVER_ERROR_name = zend_string_init_interned("FAILOVER_ERROR", sizeof("FAILOVER_ERROR") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_FAILOVER_ERROR_name, &const_FAILOVER_ERROR_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_FAILOVER_ERROR_name);
zval const_FAILOVER_DISTRIBUTE_value;
ZVAL_LONG(&const_FAILOVER_DISTRIBUTE_value, REDIS_FAILOVER_DISTRIBUTE);
zend_string *const_FAILOVER_DISTRIBUTE_name = zend_string_init_interned("FAILOVER_DISTRIBUTE", sizeof("FAILOVER_DISTRIBUTE") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_FAILOVER_DISTRIBUTE_name, &const_FAILOVER_DISTRIBUTE_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_FAILOVER_DISTRIBUTE_name);
zval const_FAILOVER_DISTRIBUTE_SLAVES_value;
ZVAL_LONG(&const_FAILOVER_DISTRIBUTE_SLAVES_value, REDIS_FAILOVER_DISTRIBUTE_SLAVES);
zend_string *const_FAILOVER_DISTRIBUTE_SLAVES_name = zend_string_init_interned("FAILOVER_DISTRIBUTE_SLAVES", sizeof("FAILOVER_DISTRIBUTE_SLAVES") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_FAILOVER_DISTRIBUTE_SLAVES_name, &const_FAILOVER_DISTRIBUTE_SLAVES_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_FAILOVER_DISTRIBUTE_SLAVES_name);
#if (PHP_VERSION_ID >= 80200)
zend_add_parameter_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "__construct", sizeof("__construct") - 1), 5, ZSTR_KNOWN(ZEND_STR_SENSITIVEPARAMETER), 0);
#endif
return class_entry;
}
static zend_class_entry *register_class_RedisClusterException(zend_class_entry *class_entry_RuntimeException)
{
zend_class_entry ce, *class_entry;
INIT_CLASS_ENTRY(ce, "RedisClusterException", class_RedisClusterException_methods);
class_entry = zend_register_internal_class_ex(&ce, class_entry_RuntimeException);
return class_entry;
}
redis-6.0.2/redis_cluster_legacy_arginfo.h 0000644 0001750 0000012 00000157524 14515245367 021507 0 ustar pyatsukhnenko wheel /* This is a generated file, edit the .stub.php file instead.
* Stub hash: 32b24ce215ff4f2299dd838fab7cbc36b81b65eb */
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster___construct, 0, 0, 1)
ZEND_ARG_INFO(0, name)
ZEND_ARG_INFO(0, seeds)
ZEND_ARG_INFO(0, timeout)
ZEND_ARG_INFO(0, read_timeout)
ZEND_ARG_INFO(0, persistent)
ZEND_ARG_INFO(0, auth)
ZEND_ARG_INFO(0, context)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster__compress, 0, 0, 1)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster__uncompress arginfo_class_RedisCluster__compress
#define arginfo_class_RedisCluster__serialize arginfo_class_RedisCluster__compress
#define arginfo_class_RedisCluster__unserialize arginfo_class_RedisCluster__compress
#define arginfo_class_RedisCluster__pack arginfo_class_RedisCluster__compress
#define arginfo_class_RedisCluster__unpack arginfo_class_RedisCluster__compress
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster__prefix, 0, 0, 1)
ZEND_ARG_INFO(0, key)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster__masters, 0, 0, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster__redir arginfo_class_RedisCluster__masters
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_acl, 0, 0, 2)
ZEND_ARG_INFO(0, key_or_address)
ZEND_ARG_INFO(0, subcmd)
ZEND_ARG_VARIADIC_INFO(0, args)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_append, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_bgrewriteaof, 0, 0, 1)
ZEND_ARG_INFO(0, key_or_address)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_bgsave arginfo_class_RedisCluster_bgrewriteaof
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_bitcount, 0, 0, 1)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, start)
ZEND_ARG_INFO(0, end)
ZEND_ARG_INFO(0, bybit)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_bitop, 0, 0, 3)
ZEND_ARG_INFO(0, operation)
ZEND_ARG_INFO(0, deskey)
ZEND_ARG_INFO(0, srckey)
ZEND_ARG_VARIADIC_INFO(0, otherkeys)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_bitpos, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, bit)
ZEND_ARG_INFO(0, start)
ZEND_ARG_INFO(0, end)
ZEND_ARG_INFO(0, bybit)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_blpop, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, timeout_or_key)
ZEND_ARG_VARIADIC_INFO(0, extra_args)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_brpop arginfo_class_RedisCluster_blpop
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_brpoplpush, 0, 0, 3)
ZEND_ARG_INFO(0, srckey)
ZEND_ARG_INFO(0, deskey)
ZEND_ARG_INFO(0, timeout)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_lmove, 0, 0, 4)
ZEND_ARG_INFO(0, src)
ZEND_ARG_INFO(0, dst)
ZEND_ARG_INFO(0, wherefrom)
ZEND_ARG_INFO(0, whereto)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_blmove, 0, 0, 5)
ZEND_ARG_INFO(0, src)
ZEND_ARG_INFO(0, dst)
ZEND_ARG_INFO(0, wherefrom)
ZEND_ARG_INFO(0, whereto)
ZEND_ARG_INFO(0, timeout)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_bzpopmax arginfo_class_RedisCluster_blpop
#define arginfo_class_RedisCluster_bzpopmin arginfo_class_RedisCluster_blpop
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_bzmpop, 0, 0, 3)
ZEND_ARG_INFO(0, timeout)
ZEND_ARG_INFO(0, keys)
ZEND_ARG_INFO(0, from)
ZEND_ARG_INFO(0, count)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_zmpop, 0, 0, 2)
ZEND_ARG_INFO(0, keys)
ZEND_ARG_INFO(0, from)
ZEND_ARG_INFO(0, count)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_blmpop arginfo_class_RedisCluster_bzmpop
#define arginfo_class_RedisCluster_lmpop arginfo_class_RedisCluster_zmpop
#define arginfo_class_RedisCluster_clearlasterror arginfo_class_RedisCluster__masters
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_client, 0, 0, 2)
ZEND_ARG_INFO(0, key_or_address)
ZEND_ARG_INFO(0, subcommand)
ZEND_ARG_INFO(0, arg)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_close arginfo_class_RedisCluster__masters
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_cluster, 0, 0, 2)
ZEND_ARG_INFO(0, key_or_address)
ZEND_ARG_INFO(0, command)
ZEND_ARG_VARIADIC_INFO(0, extra_args)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_command, 0, 0, 0)
ZEND_ARG_VARIADIC_INFO(0, extra_args)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_config, 0, 0, 2)
ZEND_ARG_INFO(0, key_or_address)
ZEND_ARG_INFO(0, subcommand)
ZEND_ARG_VARIADIC_INFO(0, extra_args)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_dbsize arginfo_class_RedisCluster_bgrewriteaof
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_copy, 0, 0, 2)
ZEND_ARG_INFO(0, src)
ZEND_ARG_INFO(0, dst)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_decr, 0, 0, 1)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, by)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_decrby arginfo_class_RedisCluster_append
#define arginfo_class_RedisCluster_decrbyfloat arginfo_class_RedisCluster_append
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_del, 0, 0, 1)
ZEND_ARG_INFO(0, key)
ZEND_ARG_VARIADIC_INFO(0, other_keys)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_discard arginfo_class_RedisCluster__masters
#define arginfo_class_RedisCluster_dump arginfo_class_RedisCluster__prefix
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_echo, 0, 0, 2)
ZEND_ARG_INFO(0, key_or_address)
ZEND_ARG_INFO(0, msg)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_eval, 0, 0, 1)
ZEND_ARG_INFO(0, script)
ZEND_ARG_INFO(0, args)
ZEND_ARG_INFO(0, num_keys)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_eval_ro arginfo_class_RedisCluster_eval
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_evalsha, 0, 0, 1)
ZEND_ARG_INFO(0, script_sha)
ZEND_ARG_INFO(0, args)
ZEND_ARG_INFO(0, num_keys)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_evalsha_ro arginfo_class_RedisCluster_evalsha
#define arginfo_class_RedisCluster_exec arginfo_class_RedisCluster__masters
#define arginfo_class_RedisCluster_exists arginfo_class_RedisCluster_del
#define arginfo_class_RedisCluster_touch arginfo_class_RedisCluster_del
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_expire, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, timeout)
ZEND_ARG_INFO(0, mode)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_expireat, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, timestamp)
ZEND_ARG_INFO(0, mode)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_expiretime arginfo_class_RedisCluster__prefix
#define arginfo_class_RedisCluster_pexpiretime arginfo_class_RedisCluster__prefix
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_flushall, 0, 0, 1)
ZEND_ARG_INFO(0, key_or_address)
ZEND_ARG_INFO(0, async)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_flushdb arginfo_class_RedisCluster_flushall
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_geoadd, 0, 0, 4)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, lng)
ZEND_ARG_INFO(0, lat)
ZEND_ARG_INFO(0, member)
ZEND_ARG_VARIADIC_INFO(0, other_triples_and_options)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_geodist, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, src)
ZEND_ARG_INFO(0, dest)
ZEND_ARG_INFO(0, unit)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_geohash, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, member)
ZEND_ARG_VARIADIC_INFO(0, other_members)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_geopos arginfo_class_RedisCluster_geohash
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_georadius, 0, 0, 5)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, lng)
ZEND_ARG_INFO(0, lat)
ZEND_ARG_INFO(0, radius)
ZEND_ARG_INFO(0, unit)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_georadius_ro arginfo_class_RedisCluster_georadius
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_georadiusbymember, 0, 0, 4)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, member)
ZEND_ARG_INFO(0, radius)
ZEND_ARG_INFO(0, unit)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_georadiusbymember_ro arginfo_class_RedisCluster_georadiusbymember
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_geosearch, 0, 0, 4)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, position)
ZEND_ARG_INFO(0, shape)
ZEND_ARG_INFO(0, unit)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_geosearchstore, 0, 0, 5)
ZEND_ARG_INFO(0, dst)
ZEND_ARG_INFO(0, src)
ZEND_ARG_INFO(0, position)
ZEND_ARG_INFO(0, shape)
ZEND_ARG_INFO(0, unit)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_get arginfo_class_RedisCluster__prefix
#define arginfo_class_RedisCluster_getbit arginfo_class_RedisCluster_append
#define arginfo_class_RedisCluster_getlasterror arginfo_class_RedisCluster__masters
#define arginfo_class_RedisCluster_getmode arginfo_class_RedisCluster__masters
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_getoption, 0, 0, 1)
ZEND_ARG_INFO(0, option)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_getrange, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, start)
ZEND_ARG_INFO(0, end)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_lcs, 0, 0, 2)
ZEND_ARG_INFO(0, key1)
ZEND_ARG_INFO(0, key2)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_getset arginfo_class_RedisCluster_append
#define arginfo_class_RedisCluster_gettransferredbytes arginfo_class_RedisCluster__masters
#define arginfo_class_RedisCluster_cleartransferredbytes arginfo_class_RedisCluster__masters
#define arginfo_class_RedisCluster_hdel arginfo_class_RedisCluster_geohash
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_hexists, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, member)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_hget arginfo_class_RedisCluster_hexists
#define arginfo_class_RedisCluster_hgetall arginfo_class_RedisCluster__prefix
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_hincrby, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, member)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_hincrbyfloat arginfo_class_RedisCluster_hincrby
#define arginfo_class_RedisCluster_hkeys arginfo_class_RedisCluster__prefix
#define arginfo_class_RedisCluster_hlen arginfo_class_RedisCluster__prefix
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_hmget, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, keys)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_hmset, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, key_values)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_hscan, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(1, iterator)
ZEND_ARG_INFO(0, pattern)
ZEND_ARG_INFO(0, count)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_hrandfield, 0, 0, 1)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_hset arginfo_class_RedisCluster_hincrby
#define arginfo_class_RedisCluster_hsetnx arginfo_class_RedisCluster_hincrby
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_hstrlen, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, field)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_hvals arginfo_class_RedisCluster__prefix
#define arginfo_class_RedisCluster_incr arginfo_class_RedisCluster_decr
#define arginfo_class_RedisCluster_incrby arginfo_class_RedisCluster_append
#define arginfo_class_RedisCluster_incrbyfloat arginfo_class_RedisCluster_append
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_info, 0, 0, 1)
ZEND_ARG_INFO(0, key_or_address)
ZEND_ARG_VARIADIC_INFO(0, sections)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_keys, 0, 0, 1)
ZEND_ARG_INFO(0, pattern)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_lastsave arginfo_class_RedisCluster_bgrewriteaof
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_lget, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, index)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_lindex arginfo_class_RedisCluster_lget
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_linsert, 0, 0, 4)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, pos)
ZEND_ARG_INFO(0, pivot)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_llen arginfo_class_RedisCluster__prefix
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_lpop, 0, 0, 1)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, count)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_lpos, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_lpush, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_VARIADIC_INFO(0, other_values)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_lpushx arginfo_class_RedisCluster_append
#define arginfo_class_RedisCluster_lrange arginfo_class_RedisCluster_getrange
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_lrem, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, count)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_lset, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, index)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_ltrim arginfo_class_RedisCluster_getrange
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_mget, 0, 0, 1)
ZEND_ARG_INFO(0, keys)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_mset, 0, 0, 1)
ZEND_ARG_INFO(0, key_values)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_msetnx arginfo_class_RedisCluster_mset
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_multi, 0, 0, 0)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_object, 0, 0, 2)
ZEND_ARG_INFO(0, subcommand)
ZEND_ARG_INFO(0, key)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_persist arginfo_class_RedisCluster__prefix
#define arginfo_class_RedisCluster_pexpire arginfo_class_RedisCluster_expire
#define arginfo_class_RedisCluster_pexpireat arginfo_class_RedisCluster_expireat
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_pfadd, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, elements)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_pfcount arginfo_class_RedisCluster__prefix
#define arginfo_class_RedisCluster_pfmerge arginfo_class_RedisCluster_hmget
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_ping, 0, 0, 1)
ZEND_ARG_INFO(0, key_or_address)
ZEND_ARG_INFO(0, message)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_psetex, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, timeout)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_psubscribe, 0, 0, 2)
ZEND_ARG_INFO(0, patterns)
ZEND_ARG_INFO(0, callback)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_pttl arginfo_class_RedisCluster__prefix
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_publish, 0, 0, 2)
ZEND_ARG_INFO(0, channel)
ZEND_ARG_INFO(0, message)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_pubsub, 0, 0, 1)
ZEND_ARG_INFO(0, key_or_address)
ZEND_ARG_VARIADIC_INFO(0, values)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_punsubscribe, 0, 0, 1)
ZEND_ARG_INFO(0, pattern)
ZEND_ARG_VARIADIC_INFO(0, other_patterns)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_randomkey arginfo_class_RedisCluster_bgrewriteaof
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_rawcommand, 0, 0, 2)
ZEND_ARG_INFO(0, key_or_address)
ZEND_ARG_INFO(0, command)
ZEND_ARG_VARIADIC_INFO(0, args)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_rename, 0, 0, 2)
ZEND_ARG_INFO(0, key_src)
ZEND_ARG_INFO(0, key_dst)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_renamenx, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, newkey)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_restore, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, timeout)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_role arginfo_class_RedisCluster_bgrewriteaof
#define arginfo_class_RedisCluster_rpop arginfo_class_RedisCluster_lpop
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_rpoplpush, 0, 0, 2)
ZEND_ARG_INFO(0, src)
ZEND_ARG_INFO(0, dst)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_rpush, 0, 0, 1)
ZEND_ARG_INFO(0, key)
ZEND_ARG_VARIADIC_INFO(0, elements)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_rpushx arginfo_class_RedisCluster_append
#define arginfo_class_RedisCluster_sadd arginfo_class_RedisCluster_lpush
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_saddarray, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, values)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_save arginfo_class_RedisCluster_bgrewriteaof
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_scan, 0, 0, 2)
ZEND_ARG_INFO(1, iterator)
ZEND_ARG_INFO(0, key_or_address)
ZEND_ARG_INFO(0, pattern)
ZEND_ARG_INFO(0, count)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_scard arginfo_class_RedisCluster__prefix
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_script, 0, 0, 1)
ZEND_ARG_INFO(0, key_or_address)
ZEND_ARG_VARIADIC_INFO(0, args)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_sdiff arginfo_class_RedisCluster_del
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_sdiffstore, 0, 0, 2)
ZEND_ARG_INFO(0, dst)
ZEND_ARG_INFO(0, key)
ZEND_ARG_VARIADIC_INFO(0, other_keys)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_set arginfo_class_RedisCluster_lpos
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_setbit, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, offset)
ZEND_ARG_INFO(0, onoff)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_setex, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, expire)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_setnx arginfo_class_RedisCluster_append
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_setoption, 0, 0, 2)
ZEND_ARG_INFO(0, option)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_setrange, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, offset)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_sinter arginfo_class_RedisCluster_del
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_sintercard, 0, 0, 1)
ZEND_ARG_INFO(0, keys)
ZEND_ARG_INFO(0, limit)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_sinterstore arginfo_class_RedisCluster_del
#define arginfo_class_RedisCluster_sismember arginfo_class_RedisCluster_append
#define arginfo_class_RedisCluster_smismember arginfo_class_RedisCluster_geohash
#define arginfo_class_RedisCluster_slowlog arginfo_class_RedisCluster_script
#define arginfo_class_RedisCluster_smembers arginfo_class_RedisCluster__prefix
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_smove, 0, 0, 3)
ZEND_ARG_INFO(0, src)
ZEND_ARG_INFO(0, dst)
ZEND_ARG_INFO(0, member)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_sort arginfo_class_RedisCluster_hrandfield
#define arginfo_class_RedisCluster_sort_ro arginfo_class_RedisCluster_hrandfield
#define arginfo_class_RedisCluster_spop arginfo_class_RedisCluster_lpop
#define arginfo_class_RedisCluster_srandmember arginfo_class_RedisCluster_lpop
#define arginfo_class_RedisCluster_srem arginfo_class_RedisCluster_lpush
#define arginfo_class_RedisCluster_sscan arginfo_class_RedisCluster_hscan
#define arginfo_class_RedisCluster_strlen arginfo_class_RedisCluster__prefix
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_subscribe, 0, 0, 2)
ZEND_ARG_INFO(0, channels)
ZEND_ARG_INFO(0, cb)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_sunion arginfo_class_RedisCluster_del
#define arginfo_class_RedisCluster_sunionstore arginfo_class_RedisCluster_sdiffstore
#define arginfo_class_RedisCluster_time arginfo_class_RedisCluster_bgrewriteaof
#define arginfo_class_RedisCluster_ttl arginfo_class_RedisCluster__prefix
#define arginfo_class_RedisCluster_type arginfo_class_RedisCluster__prefix
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_unsubscribe, 0, 0, 1)
ZEND_ARG_INFO(0, channels)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_unlink arginfo_class_RedisCluster_del
#define arginfo_class_RedisCluster_unwatch arginfo_class_RedisCluster__masters
#define arginfo_class_RedisCluster_watch arginfo_class_RedisCluster_del
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_xack, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, group)
ZEND_ARG_INFO(0, ids)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_xadd, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, id)
ZEND_ARG_INFO(0, values)
ZEND_ARG_INFO(0, maxlen)
ZEND_ARG_INFO(0, approx)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_xclaim, 0, 0, 6)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, group)
ZEND_ARG_INFO(0, consumer)
ZEND_ARG_INFO(0, min_iddle)
ZEND_ARG_INFO(0, ids)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_xdel, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, ids)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_xgroup, 0, 0, 1)
ZEND_ARG_INFO(0, operation)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, group)
ZEND_ARG_INFO(0, id_or_consumer)
ZEND_ARG_INFO(0, mkstream)
ZEND_ARG_INFO(0, entries_read)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_xautoclaim, 0, 0, 5)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, group)
ZEND_ARG_INFO(0, consumer)
ZEND_ARG_INFO(0, min_idle)
ZEND_ARG_INFO(0, start)
ZEND_ARG_INFO(0, count)
ZEND_ARG_INFO(0, justid)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_xinfo, 0, 0, 1)
ZEND_ARG_INFO(0, operation)
ZEND_ARG_INFO(0, arg1)
ZEND_ARG_INFO(0, arg2)
ZEND_ARG_INFO(0, count)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_xlen arginfo_class_RedisCluster__prefix
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_xpending, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, group)
ZEND_ARG_INFO(0, start)
ZEND_ARG_INFO(0, end)
ZEND_ARG_INFO(0, count)
ZEND_ARG_INFO(0, consumer)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_xrange, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, start)
ZEND_ARG_INFO(0, end)
ZEND_ARG_INFO(0, count)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_xread, 0, 0, 1)
ZEND_ARG_INFO(0, streams)
ZEND_ARG_INFO(0, count)
ZEND_ARG_INFO(0, block)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_xreadgroup, 0, 0, 3)
ZEND_ARG_INFO(0, group)
ZEND_ARG_INFO(0, consumer)
ZEND_ARG_INFO(0, streams)
ZEND_ARG_INFO(0, count)
ZEND_ARG_INFO(0, block)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_xrevrange arginfo_class_RedisCluster_xrange
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_xtrim, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, maxlen)
ZEND_ARG_INFO(0, approx)
ZEND_ARG_INFO(0, minid)
ZEND_ARG_INFO(0, limit)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_zadd, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, score_or_options)
ZEND_ARG_VARIADIC_INFO(0, more_scores_and_mems)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_zcard arginfo_class_RedisCluster__prefix
#define arginfo_class_RedisCluster_zcount arginfo_class_RedisCluster_getrange
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_zincrby, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, member)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_zinterstore, 0, 0, 2)
ZEND_ARG_INFO(0, dst)
ZEND_ARG_INFO(0, keys)
ZEND_ARG_INFO(0, weights)
ZEND_ARG_INFO(0, aggregate)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_zintercard arginfo_class_RedisCluster_sintercard
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_zlexcount, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, min)
ZEND_ARG_INFO(0, max)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_zpopmax, 0, 0, 1)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_zpopmin arginfo_class_RedisCluster_zpopmax
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_zrange, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, start)
ZEND_ARG_INFO(0, end)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_zrangestore, 0, 0, 4)
ZEND_ARG_INFO(0, dstkey)
ZEND_ARG_INFO(0, srckey)
ZEND_ARG_INFO(0, start)
ZEND_ARG_INFO(0, end)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_zrandmember arginfo_class_RedisCluster_hrandfield
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_zrangebylex, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, min)
ZEND_ARG_INFO(0, max)
ZEND_ARG_INFO(0, offset)
ZEND_ARG_INFO(0, count)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_zrangebyscore arginfo_class_RedisCluster_zrange
#define arginfo_class_RedisCluster_zrank arginfo_class_RedisCluster_hexists
#define arginfo_class_RedisCluster_zrem arginfo_class_RedisCluster_lpush
#define arginfo_class_RedisCluster_zremrangebylex arginfo_class_RedisCluster_zlexcount
#define arginfo_class_RedisCluster_zremrangebyrank arginfo_class_RedisCluster_zlexcount
#define arginfo_class_RedisCluster_zremrangebyscore arginfo_class_RedisCluster_zlexcount
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_zrevrange, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, min)
ZEND_ARG_INFO(0, max)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_zrevrangebylex arginfo_class_RedisCluster_zrevrange
#define arginfo_class_RedisCluster_zrevrangebyscore arginfo_class_RedisCluster_zrevrange
#define arginfo_class_RedisCluster_zrevrank arginfo_class_RedisCluster_hexists
#define arginfo_class_RedisCluster_zscan arginfo_class_RedisCluster_hscan
#define arginfo_class_RedisCluster_zscore arginfo_class_RedisCluster_hexists
#define arginfo_class_RedisCluster_zmscore arginfo_class_RedisCluster_geohash
#define arginfo_class_RedisCluster_zunionstore arginfo_class_RedisCluster_zinterstore
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_zinter, 0, 0, 1)
ZEND_ARG_INFO(0, keys)
ZEND_ARG_INFO(0, weights)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_zdiffstore, 0, 0, 2)
ZEND_ARG_INFO(0, dst)
ZEND_ARG_INFO(0, keys)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_zunion arginfo_class_RedisCluster_zinter
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_zdiff, 0, 0, 1)
ZEND_ARG_INFO(0, keys)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
ZEND_METHOD(RedisCluster, __construct);
ZEND_METHOD(RedisCluster, _compress);
ZEND_METHOD(RedisCluster, _uncompress);
ZEND_METHOD(RedisCluster, _serialize);
ZEND_METHOD(RedisCluster, _unserialize);
ZEND_METHOD(RedisCluster, _pack);
ZEND_METHOD(RedisCluster, _unpack);
ZEND_METHOD(RedisCluster, _prefix);
ZEND_METHOD(RedisCluster, _masters);
ZEND_METHOD(RedisCluster, _redir);
ZEND_METHOD(RedisCluster, acl);
ZEND_METHOD(RedisCluster, append);
ZEND_METHOD(RedisCluster, bgrewriteaof);
ZEND_METHOD(RedisCluster, bgsave);
ZEND_METHOD(RedisCluster, bitcount);
ZEND_METHOD(RedisCluster, bitop);
ZEND_METHOD(RedisCluster, bitpos);
ZEND_METHOD(RedisCluster, blpop);
ZEND_METHOD(RedisCluster, brpop);
ZEND_METHOD(RedisCluster, brpoplpush);
ZEND_METHOD(RedisCluster, lmove);
ZEND_METHOD(RedisCluster, blmove);
ZEND_METHOD(RedisCluster, bzpopmax);
ZEND_METHOD(RedisCluster, bzpopmin);
ZEND_METHOD(RedisCluster, bzmpop);
ZEND_METHOD(RedisCluster, zmpop);
ZEND_METHOD(RedisCluster, blmpop);
ZEND_METHOD(RedisCluster, lmpop);
ZEND_METHOD(RedisCluster, clearlasterror);
ZEND_METHOD(RedisCluster, client);
ZEND_METHOD(RedisCluster, close);
ZEND_METHOD(RedisCluster, cluster);
ZEND_METHOD(RedisCluster, command);
ZEND_METHOD(RedisCluster, config);
ZEND_METHOD(RedisCluster, dbsize);
ZEND_METHOD(RedisCluster, copy);
ZEND_METHOD(RedisCluster, decr);
ZEND_METHOD(RedisCluster, decrby);
ZEND_METHOD(RedisCluster, decrbyfloat);
ZEND_METHOD(RedisCluster, del);
ZEND_METHOD(RedisCluster, discard);
ZEND_METHOD(RedisCluster, dump);
ZEND_METHOD(RedisCluster, echo);
ZEND_METHOD(RedisCluster, eval);
ZEND_METHOD(RedisCluster, eval_ro);
ZEND_METHOD(RedisCluster, evalsha);
ZEND_METHOD(RedisCluster, evalsha_ro);
ZEND_METHOD(RedisCluster, exec);
ZEND_METHOD(RedisCluster, exists);
ZEND_METHOD(RedisCluster, touch);
ZEND_METHOD(RedisCluster, expire);
ZEND_METHOD(RedisCluster, expireat);
ZEND_METHOD(RedisCluster, expiretime);
ZEND_METHOD(RedisCluster, pexpiretime);
ZEND_METHOD(RedisCluster, flushall);
ZEND_METHOD(RedisCluster, flushdb);
ZEND_METHOD(RedisCluster, geoadd);
ZEND_METHOD(RedisCluster, geodist);
ZEND_METHOD(RedisCluster, geohash);
ZEND_METHOD(RedisCluster, geopos);
ZEND_METHOD(RedisCluster, georadius);
ZEND_METHOD(RedisCluster, georadius_ro);
ZEND_METHOD(RedisCluster, georadiusbymember);
ZEND_METHOD(RedisCluster, georadiusbymember_ro);
ZEND_METHOD(RedisCluster, geosearch);
ZEND_METHOD(RedisCluster, geosearchstore);
ZEND_METHOD(RedisCluster, get);
ZEND_METHOD(RedisCluster, getbit);
ZEND_METHOD(RedisCluster, getlasterror);
ZEND_METHOD(RedisCluster, getmode);
ZEND_METHOD(RedisCluster, getoption);
ZEND_METHOD(RedisCluster, getrange);
ZEND_METHOD(RedisCluster, lcs);
ZEND_METHOD(RedisCluster, getset);
ZEND_METHOD(RedisCluster, gettransferredbytes);
ZEND_METHOD(RedisCluster, cleartransferredbytes);
ZEND_METHOD(RedisCluster, hdel);
ZEND_METHOD(RedisCluster, hexists);
ZEND_METHOD(RedisCluster, hget);
ZEND_METHOD(RedisCluster, hgetall);
ZEND_METHOD(RedisCluster, hincrby);
ZEND_METHOD(RedisCluster, hincrbyfloat);
ZEND_METHOD(RedisCluster, hkeys);
ZEND_METHOD(RedisCluster, hlen);
ZEND_METHOD(RedisCluster, hmget);
ZEND_METHOD(RedisCluster, hmset);
ZEND_METHOD(RedisCluster, hscan);
ZEND_METHOD(RedisCluster, hrandfield);
ZEND_METHOD(RedisCluster, hset);
ZEND_METHOD(RedisCluster, hsetnx);
ZEND_METHOD(RedisCluster, hstrlen);
ZEND_METHOD(RedisCluster, hvals);
ZEND_METHOD(RedisCluster, incr);
ZEND_METHOD(RedisCluster, incrby);
ZEND_METHOD(RedisCluster, incrbyfloat);
ZEND_METHOD(RedisCluster, info);
ZEND_METHOD(RedisCluster, keys);
ZEND_METHOD(RedisCluster, lastsave);
ZEND_METHOD(RedisCluster, lget);
ZEND_METHOD(RedisCluster, lindex);
ZEND_METHOD(RedisCluster, linsert);
ZEND_METHOD(RedisCluster, llen);
ZEND_METHOD(RedisCluster, lpop);
ZEND_METHOD(RedisCluster, lpos);
ZEND_METHOD(RedisCluster, lpush);
ZEND_METHOD(RedisCluster, lpushx);
ZEND_METHOD(RedisCluster, lrange);
ZEND_METHOD(RedisCluster, lrem);
ZEND_METHOD(RedisCluster, lset);
ZEND_METHOD(RedisCluster, ltrim);
ZEND_METHOD(RedisCluster, mget);
ZEND_METHOD(RedisCluster, mset);
ZEND_METHOD(RedisCluster, msetnx);
ZEND_METHOD(RedisCluster, multi);
ZEND_METHOD(RedisCluster, object);
ZEND_METHOD(RedisCluster, persist);
ZEND_METHOD(RedisCluster, pexpire);
ZEND_METHOD(RedisCluster, pexpireat);
ZEND_METHOD(RedisCluster, pfadd);
ZEND_METHOD(RedisCluster, pfcount);
ZEND_METHOD(RedisCluster, pfmerge);
ZEND_METHOD(RedisCluster, ping);
ZEND_METHOD(RedisCluster, psetex);
ZEND_METHOD(RedisCluster, psubscribe);
ZEND_METHOD(RedisCluster, pttl);
ZEND_METHOD(RedisCluster, publish);
ZEND_METHOD(RedisCluster, pubsub);
ZEND_METHOD(RedisCluster, punsubscribe);
ZEND_METHOD(RedisCluster, randomkey);
ZEND_METHOD(RedisCluster, rawcommand);
ZEND_METHOD(RedisCluster, rename);
ZEND_METHOD(RedisCluster, renamenx);
ZEND_METHOD(RedisCluster, restore);
ZEND_METHOD(RedisCluster, role);
ZEND_METHOD(RedisCluster, rpop);
ZEND_METHOD(RedisCluster, rpoplpush);
ZEND_METHOD(RedisCluster, rpush);
ZEND_METHOD(RedisCluster, rpushx);
ZEND_METHOD(RedisCluster, sadd);
ZEND_METHOD(RedisCluster, saddarray);
ZEND_METHOD(RedisCluster, save);
ZEND_METHOD(RedisCluster, scan);
ZEND_METHOD(RedisCluster, scard);
ZEND_METHOD(RedisCluster, script);
ZEND_METHOD(RedisCluster, sdiff);
ZEND_METHOD(RedisCluster, sdiffstore);
ZEND_METHOD(RedisCluster, set);
ZEND_METHOD(RedisCluster, setbit);
ZEND_METHOD(RedisCluster, setex);
ZEND_METHOD(RedisCluster, setnx);
ZEND_METHOD(RedisCluster, setoption);
ZEND_METHOD(RedisCluster, setrange);
ZEND_METHOD(RedisCluster, sinter);
ZEND_METHOD(RedisCluster, sintercard);
ZEND_METHOD(RedisCluster, sinterstore);
ZEND_METHOD(RedisCluster, sismember);
ZEND_METHOD(RedisCluster, smismember);
ZEND_METHOD(RedisCluster, slowlog);
ZEND_METHOD(RedisCluster, smembers);
ZEND_METHOD(RedisCluster, smove);
ZEND_METHOD(RedisCluster, sort);
ZEND_METHOD(RedisCluster, sort_ro);
ZEND_METHOD(RedisCluster, spop);
ZEND_METHOD(RedisCluster, srandmember);
ZEND_METHOD(RedisCluster, srem);
ZEND_METHOD(RedisCluster, sscan);
ZEND_METHOD(RedisCluster, strlen);
ZEND_METHOD(RedisCluster, subscribe);
ZEND_METHOD(RedisCluster, sunion);
ZEND_METHOD(RedisCluster, sunionstore);
ZEND_METHOD(RedisCluster, time);
ZEND_METHOD(RedisCluster, ttl);
ZEND_METHOD(RedisCluster, type);
ZEND_METHOD(RedisCluster, unsubscribe);
ZEND_METHOD(RedisCluster, unlink);
ZEND_METHOD(RedisCluster, unwatch);
ZEND_METHOD(RedisCluster, watch);
ZEND_METHOD(RedisCluster, xack);
ZEND_METHOD(RedisCluster, xadd);
ZEND_METHOD(RedisCluster, xclaim);
ZEND_METHOD(RedisCluster, xdel);
ZEND_METHOD(RedisCluster, xgroup);
ZEND_METHOD(RedisCluster, xautoclaim);
ZEND_METHOD(RedisCluster, xinfo);
ZEND_METHOD(RedisCluster, xlen);
ZEND_METHOD(RedisCluster, xpending);
ZEND_METHOD(RedisCluster, xrange);
ZEND_METHOD(RedisCluster, xread);
ZEND_METHOD(RedisCluster, xreadgroup);
ZEND_METHOD(RedisCluster, xrevrange);
ZEND_METHOD(RedisCluster, xtrim);
ZEND_METHOD(RedisCluster, zadd);
ZEND_METHOD(RedisCluster, zcard);
ZEND_METHOD(RedisCluster, zcount);
ZEND_METHOD(RedisCluster, zincrby);
ZEND_METHOD(RedisCluster, zinterstore);
ZEND_METHOD(RedisCluster, zintercard);
ZEND_METHOD(RedisCluster, zlexcount);
ZEND_METHOD(RedisCluster, zpopmax);
ZEND_METHOD(RedisCluster, zpopmin);
ZEND_METHOD(RedisCluster, zrange);
ZEND_METHOD(RedisCluster, zrangestore);
ZEND_METHOD(RedisCluster, zrandmember);
ZEND_METHOD(RedisCluster, zrangebylex);
ZEND_METHOD(RedisCluster, zrangebyscore);
ZEND_METHOD(RedisCluster, zrank);
ZEND_METHOD(RedisCluster, zrem);
ZEND_METHOD(RedisCluster, zremrangebylex);
ZEND_METHOD(RedisCluster, zremrangebyrank);
ZEND_METHOD(RedisCluster, zremrangebyscore);
ZEND_METHOD(RedisCluster, zrevrange);
ZEND_METHOD(RedisCluster, zrevrangebylex);
ZEND_METHOD(RedisCluster, zrevrangebyscore);
ZEND_METHOD(RedisCluster, zrevrank);
ZEND_METHOD(RedisCluster, zscan);
ZEND_METHOD(RedisCluster, zscore);
ZEND_METHOD(RedisCluster, zmscore);
ZEND_METHOD(RedisCluster, zunionstore);
ZEND_METHOD(RedisCluster, zinter);
ZEND_METHOD(RedisCluster, zdiffstore);
ZEND_METHOD(RedisCluster, zunion);
ZEND_METHOD(RedisCluster, zdiff);
static const zend_function_entry class_RedisCluster_methods[] = {
ZEND_ME(RedisCluster, __construct, arginfo_class_RedisCluster___construct, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, _compress, arginfo_class_RedisCluster__compress, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, _uncompress, arginfo_class_RedisCluster__uncompress, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, _serialize, arginfo_class_RedisCluster__serialize, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, _unserialize, arginfo_class_RedisCluster__unserialize, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, _pack, arginfo_class_RedisCluster__pack, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, _unpack, arginfo_class_RedisCluster__unpack, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, _prefix, arginfo_class_RedisCluster__prefix, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, _masters, arginfo_class_RedisCluster__masters, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, _redir, arginfo_class_RedisCluster__redir, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, acl, arginfo_class_RedisCluster_acl, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, append, arginfo_class_RedisCluster_append, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, bgrewriteaof, arginfo_class_RedisCluster_bgrewriteaof, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, bgsave, arginfo_class_RedisCluster_bgsave, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, bitcount, arginfo_class_RedisCluster_bitcount, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, bitop, arginfo_class_RedisCluster_bitop, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, bitpos, arginfo_class_RedisCluster_bitpos, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, blpop, arginfo_class_RedisCluster_blpop, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, brpop, arginfo_class_RedisCluster_brpop, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, brpoplpush, arginfo_class_RedisCluster_brpoplpush, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lmove, arginfo_class_RedisCluster_lmove, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, blmove, arginfo_class_RedisCluster_blmove, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, bzpopmax, arginfo_class_RedisCluster_bzpopmax, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, bzpopmin, arginfo_class_RedisCluster_bzpopmin, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, bzmpop, arginfo_class_RedisCluster_bzmpop, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zmpop, arginfo_class_RedisCluster_zmpop, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, blmpop, arginfo_class_RedisCluster_blmpop, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lmpop, arginfo_class_RedisCluster_lmpop, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, clearlasterror, arginfo_class_RedisCluster_clearlasterror, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, client, arginfo_class_RedisCluster_client, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, close, arginfo_class_RedisCluster_close, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, cluster, arginfo_class_RedisCluster_cluster, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, command, arginfo_class_RedisCluster_command, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, config, arginfo_class_RedisCluster_config, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, dbsize, arginfo_class_RedisCluster_dbsize, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, copy, arginfo_class_RedisCluster_copy, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, decr, arginfo_class_RedisCluster_decr, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, decrby, arginfo_class_RedisCluster_decrby, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, decrbyfloat, arginfo_class_RedisCluster_decrbyfloat, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, del, arginfo_class_RedisCluster_del, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, discard, arginfo_class_RedisCluster_discard, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, dump, arginfo_class_RedisCluster_dump, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, echo, arginfo_class_RedisCluster_echo, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, eval, arginfo_class_RedisCluster_eval, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, eval_ro, arginfo_class_RedisCluster_eval_ro, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, evalsha, arginfo_class_RedisCluster_evalsha, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, evalsha_ro, arginfo_class_RedisCluster_evalsha_ro, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, exec, arginfo_class_RedisCluster_exec, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, exists, arginfo_class_RedisCluster_exists, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, touch, arginfo_class_RedisCluster_touch, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, expire, arginfo_class_RedisCluster_expire, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, expireat, arginfo_class_RedisCluster_expireat, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, expiretime, arginfo_class_RedisCluster_expiretime, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, pexpiretime, arginfo_class_RedisCluster_pexpiretime, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, flushall, arginfo_class_RedisCluster_flushall, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, flushdb, arginfo_class_RedisCluster_flushdb, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, geoadd, arginfo_class_RedisCluster_geoadd, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, geodist, arginfo_class_RedisCluster_geodist, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, geohash, arginfo_class_RedisCluster_geohash, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, geopos, arginfo_class_RedisCluster_geopos, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, georadius, arginfo_class_RedisCluster_georadius, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, georadius_ro, arginfo_class_RedisCluster_georadius_ro, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, georadiusbymember, arginfo_class_RedisCluster_georadiusbymember, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, georadiusbymember_ro, arginfo_class_RedisCluster_georadiusbymember_ro, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, geosearch, arginfo_class_RedisCluster_geosearch, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, geosearchstore, arginfo_class_RedisCluster_geosearchstore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, get, arginfo_class_RedisCluster_get, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, getbit, arginfo_class_RedisCluster_getbit, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, getlasterror, arginfo_class_RedisCluster_getlasterror, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, getmode, arginfo_class_RedisCluster_getmode, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, getoption, arginfo_class_RedisCluster_getoption, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, getrange, arginfo_class_RedisCluster_getrange, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lcs, arginfo_class_RedisCluster_lcs, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, getset, arginfo_class_RedisCluster_getset, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, gettransferredbytes, arginfo_class_RedisCluster_gettransferredbytes, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, cleartransferredbytes, arginfo_class_RedisCluster_cleartransferredbytes, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hdel, arginfo_class_RedisCluster_hdel, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hexists, arginfo_class_RedisCluster_hexists, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hget, arginfo_class_RedisCluster_hget, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hgetall, arginfo_class_RedisCluster_hgetall, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hincrby, arginfo_class_RedisCluster_hincrby, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hincrbyfloat, arginfo_class_RedisCluster_hincrbyfloat, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hkeys, arginfo_class_RedisCluster_hkeys, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hlen, arginfo_class_RedisCluster_hlen, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hmget, arginfo_class_RedisCluster_hmget, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hmset, arginfo_class_RedisCluster_hmset, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hscan, arginfo_class_RedisCluster_hscan, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hrandfield, arginfo_class_RedisCluster_hrandfield, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hset, arginfo_class_RedisCluster_hset, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hsetnx, arginfo_class_RedisCluster_hsetnx, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hstrlen, arginfo_class_RedisCluster_hstrlen, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, hvals, arginfo_class_RedisCluster_hvals, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, incr, arginfo_class_RedisCluster_incr, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, incrby, arginfo_class_RedisCluster_incrby, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, incrbyfloat, arginfo_class_RedisCluster_incrbyfloat, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, info, arginfo_class_RedisCluster_info, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, keys, arginfo_class_RedisCluster_keys, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lastsave, arginfo_class_RedisCluster_lastsave, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lget, arginfo_class_RedisCluster_lget, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lindex, arginfo_class_RedisCluster_lindex, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, linsert, arginfo_class_RedisCluster_linsert, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, llen, arginfo_class_RedisCluster_llen, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lpop, arginfo_class_RedisCluster_lpop, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lpos, arginfo_class_RedisCluster_lpos, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lpush, arginfo_class_RedisCluster_lpush, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lpushx, arginfo_class_RedisCluster_lpushx, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lrange, arginfo_class_RedisCluster_lrange, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lrem, arginfo_class_RedisCluster_lrem, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, lset, arginfo_class_RedisCluster_lset, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, ltrim, arginfo_class_RedisCluster_ltrim, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, mget, arginfo_class_RedisCluster_mget, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, mset, arginfo_class_RedisCluster_mset, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, msetnx, arginfo_class_RedisCluster_msetnx, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, multi, arginfo_class_RedisCluster_multi, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, object, arginfo_class_RedisCluster_object, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, persist, arginfo_class_RedisCluster_persist, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, pexpire, arginfo_class_RedisCluster_pexpire, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, pexpireat, arginfo_class_RedisCluster_pexpireat, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, pfadd, arginfo_class_RedisCluster_pfadd, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, pfcount, arginfo_class_RedisCluster_pfcount, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, pfmerge, arginfo_class_RedisCluster_pfmerge, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, ping, arginfo_class_RedisCluster_ping, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, psetex, arginfo_class_RedisCluster_psetex, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, psubscribe, arginfo_class_RedisCluster_psubscribe, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, pttl, arginfo_class_RedisCluster_pttl, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, publish, arginfo_class_RedisCluster_publish, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, pubsub, arginfo_class_RedisCluster_pubsub, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, punsubscribe, arginfo_class_RedisCluster_punsubscribe, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, randomkey, arginfo_class_RedisCluster_randomkey, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, rawcommand, arginfo_class_RedisCluster_rawcommand, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, rename, arginfo_class_RedisCluster_rename, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, renamenx, arginfo_class_RedisCluster_renamenx, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, restore, arginfo_class_RedisCluster_restore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, role, arginfo_class_RedisCluster_role, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, rpop, arginfo_class_RedisCluster_rpop, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, rpoplpush, arginfo_class_RedisCluster_rpoplpush, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, rpush, arginfo_class_RedisCluster_rpush, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, rpushx, arginfo_class_RedisCluster_rpushx, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, sadd, arginfo_class_RedisCluster_sadd, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, saddarray, arginfo_class_RedisCluster_saddarray, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, save, arginfo_class_RedisCluster_save, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, scan, arginfo_class_RedisCluster_scan, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, scard, arginfo_class_RedisCluster_scard, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, script, arginfo_class_RedisCluster_script, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, sdiff, arginfo_class_RedisCluster_sdiff, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, sdiffstore, arginfo_class_RedisCluster_sdiffstore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, set, arginfo_class_RedisCluster_set, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, setbit, arginfo_class_RedisCluster_setbit, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, setex, arginfo_class_RedisCluster_setex, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, setnx, arginfo_class_RedisCluster_setnx, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, setoption, arginfo_class_RedisCluster_setoption, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, setrange, arginfo_class_RedisCluster_setrange, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, sinter, arginfo_class_RedisCluster_sinter, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, sintercard, arginfo_class_RedisCluster_sintercard, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, sinterstore, arginfo_class_RedisCluster_sinterstore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, sismember, arginfo_class_RedisCluster_sismember, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, smismember, arginfo_class_RedisCluster_smismember, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, slowlog, arginfo_class_RedisCluster_slowlog, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, smembers, arginfo_class_RedisCluster_smembers, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, smove, arginfo_class_RedisCluster_smove, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, sort, arginfo_class_RedisCluster_sort, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, sort_ro, arginfo_class_RedisCluster_sort_ro, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, spop, arginfo_class_RedisCluster_spop, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, srandmember, arginfo_class_RedisCluster_srandmember, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, srem, arginfo_class_RedisCluster_srem, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, sscan, arginfo_class_RedisCluster_sscan, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, strlen, arginfo_class_RedisCluster_strlen, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, subscribe, arginfo_class_RedisCluster_subscribe, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, sunion, arginfo_class_RedisCluster_sunion, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, sunionstore, arginfo_class_RedisCluster_sunionstore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, time, arginfo_class_RedisCluster_time, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, ttl, arginfo_class_RedisCluster_ttl, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, type, arginfo_class_RedisCluster_type, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, unsubscribe, arginfo_class_RedisCluster_unsubscribe, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, unlink, arginfo_class_RedisCluster_unlink, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, unwatch, arginfo_class_RedisCluster_unwatch, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, watch, arginfo_class_RedisCluster_watch, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xack, arginfo_class_RedisCluster_xack, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xadd, arginfo_class_RedisCluster_xadd, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xclaim, arginfo_class_RedisCluster_xclaim, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xdel, arginfo_class_RedisCluster_xdel, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xgroup, arginfo_class_RedisCluster_xgroup, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xautoclaim, arginfo_class_RedisCluster_xautoclaim, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xinfo, arginfo_class_RedisCluster_xinfo, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xlen, arginfo_class_RedisCluster_xlen, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xpending, arginfo_class_RedisCluster_xpending, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xrange, arginfo_class_RedisCluster_xrange, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xread, arginfo_class_RedisCluster_xread, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xreadgroup, arginfo_class_RedisCluster_xreadgroup, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xrevrange, arginfo_class_RedisCluster_xrevrange, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, xtrim, arginfo_class_RedisCluster_xtrim, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zadd, arginfo_class_RedisCluster_zadd, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zcard, arginfo_class_RedisCluster_zcard, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zcount, arginfo_class_RedisCluster_zcount, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zincrby, arginfo_class_RedisCluster_zincrby, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zinterstore, arginfo_class_RedisCluster_zinterstore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zintercard, arginfo_class_RedisCluster_zintercard, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zlexcount, arginfo_class_RedisCluster_zlexcount, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zpopmax, arginfo_class_RedisCluster_zpopmax, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zpopmin, arginfo_class_RedisCluster_zpopmin, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrange, arginfo_class_RedisCluster_zrange, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrangestore, arginfo_class_RedisCluster_zrangestore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrandmember, arginfo_class_RedisCluster_zrandmember, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrangebylex, arginfo_class_RedisCluster_zrangebylex, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrangebyscore, arginfo_class_RedisCluster_zrangebyscore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrank, arginfo_class_RedisCluster_zrank, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrem, arginfo_class_RedisCluster_zrem, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zremrangebylex, arginfo_class_RedisCluster_zremrangebylex, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zremrangebyrank, arginfo_class_RedisCluster_zremrangebyrank, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zremrangebyscore, arginfo_class_RedisCluster_zremrangebyscore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrevrange, arginfo_class_RedisCluster_zrevrange, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrevrangebylex, arginfo_class_RedisCluster_zrevrangebylex, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrevrangebyscore, arginfo_class_RedisCluster_zrevrangebyscore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrevrank, arginfo_class_RedisCluster_zrevrank, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zscan, arginfo_class_RedisCluster_zscan, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zscore, arginfo_class_RedisCluster_zscore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zmscore, arginfo_class_RedisCluster_zmscore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zunionstore, arginfo_class_RedisCluster_zunionstore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zinter, arginfo_class_RedisCluster_zinter, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zdiffstore, arginfo_class_RedisCluster_zdiffstore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zunion, arginfo_class_RedisCluster_zunion, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zdiff, arginfo_class_RedisCluster_zdiff, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
static const zend_function_entry class_RedisClusterException_methods[] = {
ZEND_FE_END
};
static zend_class_entry *register_class_RedisCluster(void)
{
zend_class_entry ce, *class_entry;
INIT_CLASS_ENTRY(ce, "RedisCluster", class_RedisCluster_methods);
class_entry = zend_register_internal_class_ex(&ce, NULL);
zval const_OPT_SLAVE_FAILOVER_value;
ZVAL_LONG(&const_OPT_SLAVE_FAILOVER_value, REDIS_OPT_FAILOVER);
zend_string *const_OPT_SLAVE_FAILOVER_name = zend_string_init_interned("OPT_SLAVE_FAILOVER", sizeof("OPT_SLAVE_FAILOVER") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_OPT_SLAVE_FAILOVER_name, &const_OPT_SLAVE_FAILOVER_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_OPT_SLAVE_FAILOVER_name);
zval const_FAILOVER_NONE_value;
ZVAL_LONG(&const_FAILOVER_NONE_value, REDIS_FAILOVER_NONE);
zend_string *const_FAILOVER_NONE_name = zend_string_init_interned("FAILOVER_NONE", sizeof("FAILOVER_NONE") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_FAILOVER_NONE_name, &const_FAILOVER_NONE_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_FAILOVER_NONE_name);
zval const_FAILOVER_ERROR_value;
ZVAL_LONG(&const_FAILOVER_ERROR_value, REDIS_FAILOVER_ERROR);
zend_string *const_FAILOVER_ERROR_name = zend_string_init_interned("FAILOVER_ERROR", sizeof("FAILOVER_ERROR") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_FAILOVER_ERROR_name, &const_FAILOVER_ERROR_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_FAILOVER_ERROR_name);
zval const_FAILOVER_DISTRIBUTE_value;
ZVAL_LONG(&const_FAILOVER_DISTRIBUTE_value, REDIS_FAILOVER_DISTRIBUTE);
zend_string *const_FAILOVER_DISTRIBUTE_name = zend_string_init_interned("FAILOVER_DISTRIBUTE", sizeof("FAILOVER_DISTRIBUTE") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_FAILOVER_DISTRIBUTE_name, &const_FAILOVER_DISTRIBUTE_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_FAILOVER_DISTRIBUTE_name);
zval const_FAILOVER_DISTRIBUTE_SLAVES_value;
ZVAL_LONG(&const_FAILOVER_DISTRIBUTE_SLAVES_value, REDIS_FAILOVER_DISTRIBUTE_SLAVES);
zend_string *const_FAILOVER_DISTRIBUTE_SLAVES_name = zend_string_init_interned("FAILOVER_DISTRIBUTE_SLAVES", sizeof("FAILOVER_DISTRIBUTE_SLAVES") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_FAILOVER_DISTRIBUTE_SLAVES_name, &const_FAILOVER_DISTRIBUTE_SLAVES_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_FAILOVER_DISTRIBUTE_SLAVES_name);
return class_entry;
}
static zend_class_entry *register_class_RedisClusterException(zend_class_entry *class_entry_RuntimeException)
{
zend_class_entry ce, *class_entry;
INIT_CLASS_ENTRY(ce, "RedisClusterException", class_RedisClusterException_methods);
class_entry = zend_register_internal_class_ex(&ce, class_entry_RuntimeException);
return class_entry;
}
redis-6.0.2/redis_commands.c 0000644 0001750 0000012 00000632627 14515245367 016573 0 ustar pyatsukhnenko wheel /* -*- Mode: C; tab-width: 4 -*- */
/*
+----------------------------------------------------------------------+
| Copyright (c) 1997-2009 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Original Author: Michael Grunder |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "redis_commands.h"
#include "php_network.h"
#ifndef PHP_WIN32
#include /* TCP_KEEPALIVE */
#else
#include
#endif
#include
/* Georadius sort type */
typedef enum geoSortType {
SORT_NONE,
SORT_ASC,
SORT_DESC
} geoSortType;
/* Georadius store type */
typedef enum geoStoreType {
STORE_NONE,
STORE_COORD,
STORE_DIST
} geoStoreType;
/* Georadius options structure */
typedef struct geoOptions {
int withcoord;
int withdist;
int withhash;
long count;
zend_bool any;
geoSortType sort;
geoStoreType store;
zend_string *key;
} geoOptions;
typedef struct redisLcsOptions {
zend_bool len;
zend_bool idx;
zend_long minmatchlen;
zend_bool withmatchlen;
} redisLcsOptions;
typedef struct redisRestoreOptions {
zend_bool replace;
zend_bool absttl;
zend_long idletime;
zend_long freq;
} redisRestoreOptions;
#define REDIS_ZCMD_HAS_DST_KEY (1 << 0)
#define REDIS_ZCMD_HAS_WITHSCORES (1 << 1)
#define REDIS_ZCMD_HAS_BY_LEX_SCORE (1 << 2)
#define REDIS_ZCMD_HAS_REV (1 << 3)
#define REDIS_ZCMD_HAS_LIMIT (1 << 4)
#define REDIS_ZCMD_INT_RANGE (1 << 5)
#define REDIS_ZCMD_HAS_AGGREGATE (1 << 6)
/* ZRANGE, ZRANGEBYSCORE, ZRANGESTORE options */
typedef struct redisZcmdOptions {
zend_bool withscores;
zend_bool byscore;
zend_bool bylex;
zend_bool rev;
zend_string *aggregate;
struct {
zend_bool enabled;
zend_long offset;
zend_long count;
} limit;
} redisZcmdOptions;
/* Local passthrough macro for command construction. Given that these methods
* are generic (so they work whether the caller is Redis or RedisCluster) we
* will always have redis_sock, slot*, and */
#define REDIS_CMD_SPPRINTF(ret, kw, fmt, ...) \
redis_spprintf(redis_sock, slot, ret, kw, fmt, ##__VA_ARGS__)
/* Generic commands based on method signature and what kind of things we're
* processing. Lots of Redis commands take something like key, value, or
* key, value long. Each unique signature like this is written only once */
/* A command that takes no arguments */
int redis_empty_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
*cmd_len = REDIS_CMD_SPPRINTF(cmd, kw, "");
return SUCCESS;
}
/* Helper to construct a raw command. Given that the cluster and non cluster
* versions are different (RedisCluster needs an additional argument to direct
* the command) we take the start of our array and count */
int redis_build_raw_cmd(zval *z_args, int argc, char **cmd, int *cmd_len)
{
smart_string cmdstr = {0};
int i;
/* Make sure our first argument is a string */
if (Z_TYPE(z_args[0]) != IS_STRING) {
php_error_docref(NULL, E_WARNING,
"When sending a 'raw' command, the first argument must be a string!");
return FAILURE;
}
/* Initialize our command string */
redis_cmd_init_sstr(&cmdstr, argc-1, Z_STRVAL(z_args[0]), Z_STRLEN(z_args[0]));
for (i = 1; i < argc; i++) {
switch (Z_TYPE(z_args[i])) {
case IS_STRING:
redis_cmd_append_sstr(&cmdstr, Z_STRVAL(z_args[i]),
Z_STRLEN(z_args[i]));
break;
case IS_LONG:
redis_cmd_append_sstr_long(&cmdstr,Z_LVAL(z_args[i]));
break;
case IS_DOUBLE:
redis_cmd_append_sstr_dbl(&cmdstr,Z_DVAL(z_args[i]));
break;
default:
php_error_docref(NULL, E_WARNING,
"Raw command arguments must be scalar values!");
efree(cmdstr.c);
return FAILURE;
}
}
/* Push command and length to caller */
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
smart_string *
redis_build_script_cmd(smart_string *cmd, int argc, zval *z_args)
{
int i;
zend_string *zstr;
if (Z_TYPE(z_args[0]) != IS_STRING) {
return NULL;
}
// Branch based on the directive
if (!strcasecmp(Z_STRVAL(z_args[0]), "kill")) {
// Simple SCRIPT_KILL command
REDIS_CMD_INIT_SSTR_STATIC(cmd, argc, "SCRIPT");
redis_cmd_append_sstr(cmd, ZEND_STRL("KILL"));
} else if (!strcasecmp(Z_STRVAL(z_args[0]), "flush")) {
// Simple SCRIPT FLUSH [ASYNC | SYNC]
if (argc > 1 && (
Z_TYPE(z_args[1]) != IS_STRING ||
strcasecmp(Z_STRVAL(z_args[1]), "sync") ||
strcasecmp(Z_STRVAL(z_args[1]), "async")
)) {
return NULL;
}
REDIS_CMD_INIT_SSTR_STATIC(cmd, argc, "SCRIPT");
redis_cmd_append_sstr(cmd, ZEND_STRL("FLUSH"));
if (argc > 1) {
redis_cmd_append_sstr(cmd, Z_STRVAL(z_args[1]), Z_STRLEN(z_args[1]));
}
} else if (!strcasecmp(Z_STRVAL(z_args[0]), "load")) {
// Make sure we have a second argument, and it's not empty. If it is
// empty, we can just return an empty array (which is what Redis does)
if (argc < 2 || Z_TYPE(z_args[1]) != IS_STRING || Z_STRLEN(z_args[1]) < 1) {
return NULL;
}
// Format our SCRIPT LOAD command
REDIS_CMD_INIT_SSTR_STATIC(cmd, argc, "SCRIPT");
redis_cmd_append_sstr(cmd, ZEND_STRL("LOAD"));
redis_cmd_append_sstr(cmd, Z_STRVAL(z_args[1]), Z_STRLEN(z_args[1]));
} else if (!strcasecmp(Z_STRVAL(z_args[0]), "exists")) {
// Make sure we have a second argument
if (argc < 2) {
return NULL;
}
/* Construct our SCRIPT EXISTS command */
REDIS_CMD_INIT_SSTR_STATIC(cmd, argc, "SCRIPT");
redis_cmd_append_sstr(cmd, ZEND_STRL("EXISTS"));
for (i = 1; i < argc; ++i) {
zstr = zval_get_string(&z_args[i]);
redis_cmd_append_sstr(cmd, ZSTR_VAL(zstr), ZSTR_LEN(zstr));
zend_string_release(zstr);
}
} else {
/* Unknown directive */
return NULL;
}
return cmd;
}
/* Command that takes one optional string */
int redis_opt_str_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, char *kw,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
char *arg = NULL;
size_t arglen;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s!", &arg, &arglen) == FAILURE) {
return FAILURE;
}
if (arg != NULL) {
*cmd_len = REDIS_CMD_SPPRINTF(cmd, kw, "s", arg, arglen);
} else {
*cmd_len = REDIS_CMD_SPPRINTF(cmd, kw, "");
}
return SUCCESS;
}
/* Generic command where we just take a string and do nothing to it*/
int redis_str_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, char *kw,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
char *arg;
size_t arg_len;
// Parse args
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &arg, &arg_len)
==FAILURE)
{
return FAILURE;
}
// Build the command without molesting the string
*cmd_len = REDIS_CMD_SPPRINTF(cmd, kw, "s", arg, arg_len);
return SUCCESS;
}
/* Key, long, zval (serialized) */
int redis_key_long_val_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
char *key = NULL;
size_t key_len;
zend_long expire;
zval *z_val;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "slz", &key, &key_len,
&expire, &z_val) == FAILURE)
{
return FAILURE;
}
*cmd_len = REDIS_CMD_SPPRINTF(cmd, kw, "klv", key, key_len, expire, z_val);
return SUCCESS;
}
/* Generic key, long, string (unserialized) */
int redis_key_long_str_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
char *key, *val;
size_t key_len, val_len;
zend_long lval;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sls", &key, &key_len,
&lval, &val, &val_len) == FAILURE)
{
return FAILURE;
}
*cmd_len = REDIS_CMD_SPPRINTF(cmd, kw, "kds", key, key_len, (int)lval, val, val_len);
return SUCCESS;
}
/* Generic command construction when we just take a key and value */
int redis_kv_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
char *key;
size_t key_len;
zval *z_val;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz", &key, &key_len,
&z_val) == FAILURE)
{
return FAILURE;
}
*cmd_len = REDIS_CMD_SPPRINTF(cmd, kw, "kv", key, key_len, z_val);
return SUCCESS;
}
/* Generic command that takes a key and an unserialized value */
int redis_key_str_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
char *key, *val;
size_t key_len, val_len;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &key, &key_len,
&val, &val_len) == FAILURE)
{
return FAILURE;
}
// Construct command
*cmd_len = REDIS_CMD_SPPRINTF(cmd, kw, "ks", key, key_len, val, val_len);
return SUCCESS;
}
/* Key, string, string without serialization (ZCOUNT, ZREMRANGEBYSCORE) */
int redis_key_str_str_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
char *k, *v1, *v2;
size_t klen, v1len, v2len;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss", &k, &klen,
&v1, &v1len, &v2, &v2len) == FAILURE)
{
return FAILURE;
}
*cmd_len = REDIS_CMD_SPPRINTF(cmd, kw, "kss", k, klen, v1, v1len, v2, v2len);
// Success!
return SUCCESS;
}
/* Generic command that takes two keys */
int redis_key_key_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
zend_string *key1 = NULL, *key2 = NULL;
smart_string cmdstr = {0};
short slot2;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_STR(key1)
Z_PARAM_STR(key2)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
redis_cmd_init_sstr(&cmdstr, 2, kw, strlen(kw));
redis_cmd_append_sstr_key_zstr(&cmdstr, key1, redis_sock, slot);
redis_cmd_append_sstr_key_zstr(&cmdstr, key2, redis_sock, slot ? &slot2 : NULL);
if (slot && *slot != slot2) {
php_error_docref(0, E_WARNING, "Keys don't hash to the same slot");
smart_string_free(&cmdstr);
return FAILURE;
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* Generic command construction where we take a key and a long */
int redis_key_long_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
zend_string *key = NULL;
zend_long lval = 0;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_STR(key)
Z_PARAM_LONG(lval)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
*cmd_len = REDIS_CMD_SPPRINTF(cmd, kw, "kl", ZSTR_VAL(key), ZSTR_LEN(key), lval);
return SUCCESS;
}
/* long, long */
int redis_long_long_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
zend_long l1 = 0, l2 = 0;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_LONG(l1)
Z_PARAM_LONG(l2)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
*cmd_len = REDIS_CMD_SPPRINTF(cmd, kw, "ll", l1, l2);
return SUCCESS;
}
/* key, long, long */
int redis_key_long_long_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
char *key;
size_t key_len;
zend_long val1, val2;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sll", &key, &key_len,
&val1, &val2) == FAILURE)
{
return FAILURE;
}
*cmd_len = REDIS_CMD_SPPRINTF(cmd, kw, "kll", key, key_len, val1, val2);
return SUCCESS;
}
/* Generic command where we take a single key */
int redis_key_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
char *key;
size_t key_len;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &key, &key_len)
==FAILURE)
{
return FAILURE;
}
*cmd_len = REDIS_CMD_SPPRINTF(cmd, kw, "k", key, key_len);
return SUCCESS;
}
int
redis_failover_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
int argc;
smart_string cmdstr = {0};
zend_bool abort = 0, force = 0;
zend_long timeout = 0, port = 0;
zend_string *zkey, *host = NULL;
zval *z_to = NULL, *z_ele;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|a!bl",
&z_to, &abort, &timeout) == FAILURE)
{
return FAILURE;
}
if (z_to != NULL) {
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(z_to), zkey, z_ele) {
if (zkey != NULL) {
ZVAL_DEREF(z_ele);
if (zend_string_equals_literal_ci(zkey, "host")) {
host = zval_get_string(z_ele);
} else if (zend_string_equals_literal_ci(zkey, "port")) {
port = zval_get_long(z_ele);
} else if (zend_string_equals_literal_ci(zkey, "force")) {
force = zval_is_true(z_ele);
}
}
} ZEND_HASH_FOREACH_END();
if (!host || !port) {
php_error_docref(NULL, E_WARNING, "host and port must be provided!");
if (host) zend_string_release(host);
return FAILURE;
}
}
argc = (host && port ? 3 + force : 0) + abort + (timeout > 0 ? 2 : 0);
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc, "FAILOVER");
if (host && port) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "TO");
redis_cmd_append_sstr_zstr(&cmdstr, host);
redis_cmd_append_sstr_int(&cmdstr, port);
if (force) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "FORCE");
}
zend_string_release(host);
}
if (abort) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "ABORT");
}
if (timeout > 0) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "TIMEOUT");
redis_cmd_append_sstr_long(&cmdstr, timeout);
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
int redis_flush_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx)
{
smart_string cmdstr = {0};
zend_bool sync = 0;
zend_bool is_null = 1;
ZEND_PARSE_PARAMETERS_START(0, 1)
Z_PARAM_OPTIONAL
Z_PARAM_BOOL_OR_NULL(sync, is_null)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
redis_cmd_init_sstr(&cmdstr, !is_null, kw, strlen(kw));
if (!is_null) {
ZEND_ASSERT(sync == 0 || sync == 1);
if (sync == 0) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "ASYNC");
} else {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "SYNC");
}
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* Generic command where we take a key and a double */
int redis_key_dbl_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
char *key;
size_t key_len;
double val;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sd", &key, &key_len,
&val) == FAILURE)
{
return FAILURE;
}
*cmd_len = REDIS_CMD_SPPRINTF(cmd, kw, "kf", key, key_len, val);
return SUCCESS;
}
/* Generic to construct SCAN and variant commands */
int redis_fmt_scan_cmd(char **cmd, REDIS_SCAN_TYPE type, char *key, int key_len,
long it, char *pat, int pat_len, long count)
{
static char *kw[] = {"SCAN","SSCAN","HSCAN","ZSCAN"};
int argc;
smart_string cmdstr = {0};
// Figure out our argument count
argc = 1 + (type!=TYPE_SCAN) + (pat_len>0?2:0) + (count>0?2:0);
redis_cmd_init_sstr(&cmdstr, argc, kw[type], strlen(kw[type]));
// Append our key if it's not a regular SCAN command
if (type != TYPE_SCAN) {
redis_cmd_append_sstr(&cmdstr, key, key_len);
}
// Append cursor
redis_cmd_append_sstr_long(&cmdstr, it);
// Append count if we've got one
if (count) {
redis_cmd_append_sstr(&cmdstr, ZEND_STRL("COUNT"));
redis_cmd_append_sstr_long(&cmdstr, count);
}
// Append pattern if we've got one
if (pat_len) {
redis_cmd_append_sstr(&cmdstr, ZEND_STRL("MATCH"));
redis_cmd_append_sstr(&cmdstr,pat,pat_len);
}
// Push command to the caller, return length
*cmd = cmdstr.c;
return cmdstr.len;
}
void redis_get_zcmd_options(redisZcmdOptions *dst, zval *src, int flags) {
zval *zv, *zoff, *zcnt;
zend_string *key;
ZEND_ASSERT(dst != NULL);
memset(dst, 0, sizeof(*dst));
if (src == NULL)
return;
if (Z_TYPE_P(src) != IS_ARRAY) {
if (Z_TYPE_P(src) == IS_TRUE && (flags & REDIS_ZCMD_HAS_WITHSCORES))
dst->withscores = 1;
return;
}
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(src), key, zv) {
ZVAL_DEREF(zv);
if (key) {
if ((flags & REDIS_ZCMD_HAS_WITHSCORES) && zend_string_equals_literal_ci(key, "WITHSCORES"))
dst->withscores = zval_is_true(zv);
else if ((flags & REDIS_ZCMD_HAS_LIMIT) && zend_string_equals_literal_ci(key, "LIMIT") &&
Z_TYPE_P(zv) == IS_ARRAY)
{
if ((zoff = zend_hash_index_find(Z_ARRVAL_P(zv), 0)) != NULL &&
(zcnt = zend_hash_index_find(Z_ARRVAL_P(zv), 1)) != NULL)
{
dst->limit.enabled = 1;
dst->limit.offset = zval_get_long(zoff);
dst->limit.count = zval_get_long(zcnt);
} else {
php_error_docref(NULL, E_WARNING, "LIMIT offset and count must be an array with twe elements");
}
} else if ((flags & REDIS_ZCMD_HAS_AGGREGATE && zend_string_equals_literal_ci(key, "AGGREGATE")) &&
Z_TYPE_P(zv) == IS_STRING)
{
if (Z_TYPE_P(zv) != IS_STRING || (!zend_string_equals_literal_ci(Z_STR_P(zv), "SUM") &&
!zend_string_equals_literal_ci(Z_STR_P(zv), "MIN") &&
!zend_string_equals_literal_ci(Z_STR_P(zv), "MAX")))
{
php_error_docref(NULL, E_WARNING, "Valid AGGREGATE options are 'SUM', 'MIN', or 'MAX'");
} else {
dst->aggregate = Z_STR_P(zv);
}
}
} else if (Z_TYPE_P(zv) == IS_STRING) {
key = Z_STR_P(zv);
if ((flags & REDIS_ZCMD_HAS_BY_LEX_SCORE) && zend_string_equals_literal_ci(key, "BYSCORE"))
dst->byscore = 1, dst->bylex = 0;
else if ((flags & REDIS_ZCMD_HAS_BY_LEX_SCORE) && zend_string_equals_literal_ci(key, "BYLEX"))
dst->bylex = 1, dst->byscore = 0;
else if ((flags & REDIS_ZCMD_HAS_REV) && zend_string_equals_literal_ci(key, "REV"))
dst->rev = 1;
else if ((flags & REDIS_ZCMD_HAS_WITHSCORES && zend_string_equals_literal_ci(key, "WITHSCORES")))
dst->withscores = 1;
}
} ZEND_HASH_FOREACH_END();
}
// + ZRANGE key start stop [BYSCORE | BYLEX] [REV] [LIMIT offset count] [WITHSCORES]
// + ZRANGESTORE dst src min max [BYSCORE | BYLEX] [REV] [LIMIT offset count]
// + ZREVRANGE key start stop [WITHSCORES]
// + ZRANGEBYSCORE key min max [LIMIT offset count] [WITHSCORES]
// + ZREVRANGEBYSCORE key max min [LIMIT offset count] [WITHSCORES]
// - ZRANGEBYLEX key min max [LIMIT offset count]
// - ZREVRANGEBYLEX key max min [LIMIT offset count]
// - ZDIFF [WITHSCORES]
// - ZUNION [WITHSCORES] [AGGREGATE X]
// - ZINTER [WITHSCORES] [AGGREGATE X]
static int redis_get_zcmd_flags(const char *kw) {
size_t len = strlen(kw);
if (REDIS_STRICMP_STATIC(kw, len, "ZRANGESTORE")) {
return REDIS_ZCMD_HAS_DST_KEY |
REDIS_ZCMD_HAS_WITHSCORES |
REDIS_ZCMD_HAS_BY_LEX_SCORE |
REDIS_ZCMD_HAS_REV |
REDIS_ZCMD_HAS_LIMIT;
} else if (REDIS_STRICMP_STATIC(kw, len, "ZRANGE")) {
return REDIS_ZCMD_HAS_WITHSCORES |
REDIS_ZCMD_HAS_BY_LEX_SCORE |
REDIS_ZCMD_HAS_REV |
REDIS_ZCMD_HAS_LIMIT;
} else if (REDIS_STRICMP_STATIC(kw, len, "ZREVRANGE")) {
return REDIS_ZCMD_HAS_WITHSCORES |
REDIS_ZCMD_INT_RANGE;
} else if (REDIS_STRICMP_STATIC(kw, len, "ZRANGEBYSCORE") ||
REDIS_STRICMP_STATIC(kw, len, "ZREVRANGEBYSCORE"))
{
return REDIS_ZCMD_HAS_LIMIT |
REDIS_ZCMD_HAS_WITHSCORES;
} else if (REDIS_STRICMP_STATIC(kw, len, "ZRANGEBYLEX") ||
REDIS_STRICMP_STATIC(kw, len, "ZREVRANGEBYLEX"))
{
return REDIS_ZCMD_HAS_LIMIT;
} else if (REDIS_STRICMP_STATIC(kw, len, "ZDIFF")) {
return REDIS_ZCMD_HAS_WITHSCORES;
} else if (REDIS_STRICMP_STATIC(kw, len, "ZINTER") ||
REDIS_STRICMP_STATIC(kw, len, "ZUNION"))
{
return REDIS_ZCMD_HAS_WITHSCORES |
REDIS_ZCMD_HAS_AGGREGATE;
}
/* Reaching this line means a compile-time error */
ZEND_ASSERT(0);
}
/* Validate ZLEX* min/max argument strings */
static int validate_zlex_arg(const char *str, size_t len) {
return (len > 1 && (*str == '[' || *str == '(')) ||
(len == 1 && (*str == '+' || *str == '-'));
}
static int validate_zlex_arg_zval(zval *z) {
return Z_TYPE_P(z) == IS_STRING && validate_zlex_arg(Z_STRVAL_P(z), Z_STRLEN_P(z));
}
int redis_zrange_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
zval *zoptions = NULL, *zstart = NULL, *zend = NULL;
zend_string *dst = NULL, *src = NULL;
zend_long start = 0, end = 0;
smart_string cmdstr = {0};
redisZcmdOptions opt;
int min_argc, flags;
short slot2;
flags = redis_get_zcmd_flags(kw);
min_argc = 3 + (flags & REDIS_ZCMD_HAS_DST_KEY);
ZEND_PARSE_PARAMETERS_START(min_argc, min_argc + 1)
if (flags & REDIS_ZCMD_HAS_DST_KEY) {
Z_PARAM_STR(dst)
}
Z_PARAM_STR(src)
if (flags & REDIS_ZCMD_INT_RANGE) {
Z_PARAM_LONG(start)
Z_PARAM_LONG(end)
} else {
Z_PARAM_ZVAL(zstart)
Z_PARAM_ZVAL(zend)
}
Z_PARAM_OPTIONAL
Z_PARAM_ZVAL_OR_NULL(zoptions)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
redis_get_zcmd_options(&opt, zoptions, flags);
if (opt.bylex) {
ZEND_ASSERT(!(flags & REDIS_ZCMD_INT_RANGE));
if (!validate_zlex_arg_zval(zstart) || !validate_zlex_arg_zval(zend)) {
php_error_docref(NULL, E_WARNING, "Legographical args must start with '[' or '(' or be '+' or '-'");
return FAILURE;
}
}
redis_cmd_init_sstr(&cmdstr, min_argc + !!opt.bylex + !!opt.byscore +
!!opt.rev + !!opt.withscores +
(opt.limit.enabled ? 3 : 0), kw, strlen(kw));
if (flags & REDIS_ZCMD_HAS_DST_KEY)
redis_cmd_append_sstr_key_zstr(&cmdstr, dst, redis_sock, slot);
redis_cmd_append_sstr_key_zstr(&cmdstr, src, redis_sock, &slot2);
/* Protect the user from crossslot errors */
if ((flags & REDIS_ZCMD_HAS_DST_KEY) && slot && *slot != slot2) {
php_error_docref(NULL, E_WARNING, "destination and source keys must map to the same slot");
efree(cmdstr.c);
return FAILURE;
}
if (flags & REDIS_ZCMD_INT_RANGE) {
redis_cmd_append_sstr_long(&cmdstr, start);
redis_cmd_append_sstr_long(&cmdstr, end);
} else {
redis_cmd_append_sstr_zval(&cmdstr, zstart, NULL);
redis_cmd_append_sstr_zval(&cmdstr, zend, NULL);
}
REDIS_CMD_APPEND_SSTR_OPT_STATIC(&cmdstr, opt.byscore, "BYSCORE");
REDIS_CMD_APPEND_SSTR_OPT_STATIC(&cmdstr, opt.bylex, "BYLEX");
REDIS_CMD_APPEND_SSTR_OPT_STATIC(&cmdstr, opt.rev, "REV");
if (opt.limit.enabled) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "LIMIT");
redis_cmd_append_sstr_long(&cmdstr, opt.limit.offset);
redis_cmd_append_sstr_long(&cmdstr, opt.limit.count);
}
REDIS_CMD_APPEND_SSTR_OPT_STATIC(&cmdstr, opt.withscores, "WITHSCORES");
if (slot) *slot = slot2;
*ctx = opt.withscores ? PHPREDIS_CTX_PTR : NULL;
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
static int redis_build_config_get_cmd(smart_string *dst, zval *val) {
zend_string *zstr;
int ncfg;
zval *zv;
if (val == NULL || (Z_TYPE_P(val) != IS_STRING && Z_TYPE_P(val) != IS_ARRAY)) {
php_error_docref(NULL, E_WARNING, "Must pass a string or array of values to CONFIG GET");
return FAILURE;
} else if (Z_TYPE_P(val) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(val)) == 0) {
php_error_docref(NULL, E_WARNING, "Cannot pass an empty array to CONFIG GET");
return FAILURE;
}
ncfg = Z_TYPE_P(val) == IS_STRING ? 1 : zend_hash_num_elements(Z_ARRVAL_P(val));
REDIS_CMD_INIT_SSTR_STATIC(dst, 1 + ncfg, "CONFIG");
REDIS_CMD_APPEND_SSTR_STATIC(dst, "GET");
if (Z_TYPE_P(val) == IS_STRING) {
redis_cmd_append_sstr_zstr(dst, Z_STR_P(val));
} else {
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(val), zv) {
ZVAL_DEREF(zv);
zstr = zval_get_string(zv);
redis_cmd_append_sstr_zstr(dst, zstr);
zend_string_release(zstr);
} ZEND_HASH_FOREACH_END();
}
return SUCCESS;
}
static int redis_build_config_set_cmd(smart_string *dst, zval *key, zend_string *val) {
zend_string *zkey, *zstr;
zval *zv;
/* Legacy case: CONFIG SET */
if (key != NULL && val != NULL) {
REDIS_CMD_INIT_SSTR_STATIC(dst, 3, "CONFIG");
REDIS_CMD_APPEND_SSTR_STATIC(dst, "SET");
zstr = zval_get_string(key);
redis_cmd_append_sstr_zstr(dst, zstr);
zend_string_release(zstr);
redis_cmd_append_sstr_zstr(dst, val);
return SUCCESS;
}
/* Now we must have an array with at least one element */
if (key == NULL || Z_TYPE_P(key) != IS_ARRAY || zend_hash_num_elements(Z_ARRVAL_P(key)) == 0) {
php_error_docref(NULL, E_WARNING, "Must either pass two strings to CONFIG SET or a non-empty array of values");
return FAILURE;
}
REDIS_CMD_INIT_SSTR_STATIC(dst, 1 + (2 * zend_hash_num_elements(Z_ARRVAL_P(key))), "CONFIG");
REDIS_CMD_APPEND_SSTR_STATIC(dst, "SET");
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(key), zkey, zv) {
if (zkey == NULL)
goto fail;
ZVAL_DEREF(zv);
redis_cmd_append_sstr_zstr(dst, zkey);
zstr = zval_get_string(zv);
redis_cmd_append_sstr_zstr(dst, zstr);
zend_string_release(zstr);
} ZEND_HASH_FOREACH_END();
return SUCCESS;
fail:
php_error_docref(NULL, E_WARNING, "Must pass an associate array of config keys and values");
efree(dst->c);
memset(dst, 0, sizeof(*dst));
return FAILURE;
}
int
redis_config_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
zend_string *op = NULL, *arg = NULL;
smart_string cmdstr = {0};
int res = FAILURE;
zval *key = NULL;
ZEND_PARSE_PARAMETERS_START(1, 3)
Z_PARAM_STR(op)
Z_PARAM_OPTIONAL
Z_PARAM_ZVAL_OR_NULL(key)
Z_PARAM_STR_OR_NULL(arg)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
if (zend_string_equals_literal_ci(op, "RESETSTAT") ||
zend_string_equals_literal_ci(op, "REWRITE"))
{
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 1, "CONFIG");
redis_cmd_append_sstr_zstr(&cmdstr, op);
*ctx = redis_boolean_response;
res = SUCCESS;
} else if (zend_string_equals_literal_ci(op, "GET")) {
res = redis_build_config_get_cmd(&cmdstr, key);
*ctx = redis_mbulk_reply_zipped_raw;
} else if (zend_string_equals_literal_ci(op, "SET")) {
res = redis_build_config_set_cmd(&cmdstr, key, arg);
*ctx = redis_boolean_response;
} else {
php_error_docref(NULL, E_WARNING, "Unknown operation '%s'", ZSTR_VAL(op));
return FAILURE;
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return res;
}
int
redis_function_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
smart_string cmdstr = {0};
zend_string *op = NULL, *arg;
zval *argv = NULL;
int i, argc = 0;
ZEND_PARSE_PARAMETERS_START(1, -1)
Z_PARAM_STR(op)
Z_PARAM_OPTIONAL
Z_PARAM_VARIADIC('*', argv, argc)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
for (i = 0; i < argc; ++i) {
if (Z_TYPE(argv[i]) != IS_STRING) {
php_error_docref(NULL, E_WARNING, "invalid argument");
return FAILURE;
}
}
if (zend_string_equals_literal_ci(op, "DELETE")) {
if (argc < 1) {
php_error_docref(NULL, E_WARNING, "argument required");
return FAILURE;
}
} else if (zend_string_equals_literal_ci(op, "DUMP")) {
*ctx = PHPREDIS_CTX_PTR;
} else if (zend_string_equals_literal_ci(op, "FLUSH")) {
if (argc > 0 &&
!zend_string_equals_literal_ci(Z_STR(argv[0]), "SYNC") &&
!zend_string_equals_literal_ci(Z_STR(argv[0]), "ASYNC")
) {
php_error_docref(NULL, E_WARNING, "invalid argument");
return FAILURE;
}
} else if (zend_string_equals_literal_ci(op, "KILL")) {
// noop
} else if (zend_string_equals_literal_ci(op, "LIST")) {
if (argc > 0) {
if (zend_string_equals_literal_ci(Z_STR(argv[0]), "LIBRARYNAME")) {
if (argc < 2) {
php_error_docref(NULL, E_WARNING, "argument required");
return FAILURE;
}
} else if (!zend_string_equals_literal_ci(Z_STR(argv[0]), "WITHCODE")) {
php_error_docref(NULL, E_WARNING, "invalid argument");
return FAILURE;
}
}
*ctx = PHPREDIS_CTX_PTR + 1;
} else if (zend_string_equals_literal_ci(op, "LOAD")) {
if (argc < 1 || (
zend_string_equals_literal_ci(Z_STR(argv[0]), "REPLACE") && argc < 2
)) {
php_error_docref(NULL, E_WARNING, "argument required");
return FAILURE;
}
*ctx = PHPREDIS_CTX_PTR;
} else if (zend_string_equals_literal_ci(op, "RESTORE")) {
if (argc < 1 || (
argc > 1 &&
!zend_string_equals_literal_ci(Z_STR(argv[1]), "FLUSH") &&
!zend_string_equals_literal_ci(Z_STR(argv[1]), "APPEND") &&
!zend_string_equals_literal_ci(Z_STR(argv[1]), "REPLACE")
)) {
php_error_docref(NULL, E_WARNING, "invalid argument");
return FAILURE;
}
} else if (zend_string_equals_literal_ci(op, "STATS")) {
*ctx = PHPREDIS_CTX_PTR + 1;
} else {
php_error_docref(NULL, E_WARNING, "Unknown operation '%s'", ZSTR_VAL(op));
return FAILURE;
}
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 1 + argc, "FUNCTION");
redis_cmd_append_sstr_zstr(&cmdstr, op);
for (i = 0; i < argc; i++) {
arg = zval_get_string(&argv[i]);
redis_cmd_append_sstr_zstr(&cmdstr, arg);
zend_string_release(arg);
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
int
redis_fcall_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx)
{
HashTable *keys = NULL, *args = NULL;
smart_string cmdstr = {0};
zend_string *fn = NULL;
zval *zv;
ZEND_PARSE_PARAMETERS_START(1, 3)
Z_PARAM_STR(fn)
Z_PARAM_OPTIONAL
Z_PARAM_ARRAY_HT(keys)
Z_PARAM_ARRAY_HT(args)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
redis_cmd_init_sstr(&cmdstr, 2 + (keys ? zend_hash_num_elements(keys) : 0) +
(args ? zend_hash_num_elements(args) : 0), kw, strlen(kw));
redis_cmd_append_sstr_zstr(&cmdstr, fn);
redis_cmd_append_sstr_long(&cmdstr, keys ? zend_hash_num_elements(keys) : 0);
if (keys != NULL) {
ZEND_HASH_FOREACH_VAL(keys, zv) {
redis_cmd_append_sstr_key_zval(&cmdstr, zv, redis_sock, slot);
} ZEND_HASH_FOREACH_END();
}
if (args != NULL) {
ZEND_HASH_FOREACH_VAL(args, zv) {
redis_cmd_append_sstr_zval(&cmdstr, zv, redis_sock);
} ZEND_HASH_FOREACH_END();
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
int
redis_zrandmember_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
char *key;
int count = 0;
size_t key_len;
smart_string cmdstr = {0};
zend_bool withscores = 0;
zval *z_opts = NULL, *z_ele;
zend_string *zkey;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|a",
&key, &key_len, &z_opts) == FAILURE)
{
return FAILURE;
}
if (z_opts != NULL) {
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(z_opts), zkey, z_ele) {
if (zkey != NULL) {
ZVAL_DEREF(z_ele);
if (zend_string_equals_literal_ci(zkey, "count")) {
count = zval_get_long(z_ele);
} else if (zend_string_equals_literal_ci(zkey, "withscores")) {
withscores = zval_is_true(z_ele);
}
}
} ZEND_HASH_FOREACH_END();
}
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 1 + (count != 0) + withscores, "ZRANDMEMBER");
redis_cmd_append_sstr_key(&cmdstr, key, key_len, redis_sock, slot);
if (count != 0) {
redis_cmd_append_sstr_long(&cmdstr, count);
*ctx = PHPREDIS_CTX_PTR;
}
if (withscores) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "WITHSCORES");
*ctx = PHPREDIS_CTX_PTR + 1;
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
int
redis_zdiff_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
zval *z_keys, *z_opts = NULL, *z_key;
redisZcmdOptions opts = {0};
smart_string cmdstr = {0};
int numkeys, flags;
short s2 = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|a",
&z_keys, &z_opts) == FAILURE)
{
return FAILURE;
}
if ((numkeys = zend_hash_num_elements(Z_ARRVAL_P(z_keys))) == 0) {
return FAILURE;
}
flags = redis_get_zcmd_flags("ZDIFF");
redis_get_zcmd_options(&opts, z_opts, flags);
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 1 + numkeys + opts.withscores, "ZDIFF");
redis_cmd_append_sstr_long(&cmdstr, numkeys);
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(z_keys), z_key) {
ZVAL_DEREF(z_key);
redis_cmd_append_sstr_key_zval(&cmdstr, z_key, redis_sock, slot);
if (slot && s2 && s2 != *slot) {
php_error_docref(NULL, E_WARNING, "Not all keys map to the same slot!");
efree(cmdstr.c);
return FAILURE;
}
if (slot) s2 = *slot;
} ZEND_HASH_FOREACH_END();
if (opts.withscores) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "WITHSCORES");
*ctx = PHPREDIS_CTX_PTR;
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
static int redis_cmd_append_sstr_score(smart_string *dst, zval *score) {
zend_uchar type;
zend_long lval;
size_t cmdlen;
double dval;
/* Get current command length */
cmdlen = dst->len;
if (Z_TYPE_P(score) == IS_LONG) {
redis_cmd_append_sstr_long(dst, Z_LVAL_P(score));
} else if (Z_TYPE_P(score) == IS_DOUBLE) {
redis_cmd_append_sstr_dbl(dst, Z_DVAL_P(score));
} else if (Z_TYPE_P(score) == IS_STRING) {
type = is_numeric_string(Z_STRVAL_P(score), Z_STRLEN_P(score), &lval, &dval, 0);
if (type == IS_LONG) {
redis_cmd_append_sstr_long(dst, lval);
} else if (type == IS_DOUBLE) {
redis_cmd_append_sstr_dbl(dst, dval);
} else if (zend_string_equals_literal_ci(Z_STR_P(score), "-inf") ||
zend_string_equals_literal_ci(Z_STR_P(score), "+inf") ||
zend_string_equals_literal_ci(Z_STR_P(score), "inf"))
{
redis_cmd_append_sstr_zstr(dst, Z_STR_P(score));
}
}
/* Success if we appended something */
if (dst->len > cmdlen)
return SUCCESS;
/* Nothing appended, failure */
php_error_docref(NULL, E_WARNING, "scores must be numeric or '-inf', 'inf', '+inf'");
return FAILURE;
}
int redis_intercard_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
smart_string cmdstr = {0};
zend_long limit = -1;
HashTable *keys;
zend_string *key;
zval *zv;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_ARRAY_HT(keys)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(limit)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
if (zend_hash_num_elements(keys) == 0) {
php_error_docref(NULL, E_WARNING, "Must pass at least one key");
return FAILURE;
} else if (ZEND_NUM_ARGS() == 2 && limit < 0) {
php_error_docref(NULL, E_WARNING, "LIMIT cannot be negative");
return FAILURE;
}
redis_cmd_init_sstr(&cmdstr, 1 + zend_hash_num_elements(keys) + (limit > 0 ? 2 : 0), kw, strlen(kw));
redis_cmd_append_sstr_long(&cmdstr, zend_hash_num_elements(keys));
if (slot) *slot = -1;
ZEND_HASH_FOREACH_VAL(keys, zv) {
key = redis_key_prefix_zval(redis_sock, zv);
if (slot) {
if (*slot == -1) {
*slot = cluster_hash_key_zstr(key);
} else if (*slot != cluster_hash_key_zstr(key)) {
php_error_docref(NULL, E_WARNING, "All keys don't hash to the same slot");
efree(cmdstr.c);
zend_string_release(key);
return FAILURE;
}
}
redis_cmd_append_sstr_zstr(&cmdstr, key);
zend_string_release(key);
} ZEND_HASH_FOREACH_END();
if (limit > 0) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "LIMIT");
redis_cmd_append_sstr_long(&cmdstr, limit);
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
int redis_replicaof_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
zend_string *host = NULL;
zend_long port = 6379;
ZEND_PARSE_PARAMETERS_START(0, 2)
Z_PARAM_OPTIONAL
Z_PARAM_STR(host)
Z_PARAM_LONG(port)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
if (port < 0 || port > UINT16_MAX) {
php_error_docref(NULL, E_WARNING, "Invalid port %ld", (long)port);
return FAILURE;
}
if (ZEND_NUM_ARGS() == 2) {
*cmd_len = REDIS_SPPRINTF(cmd, kw, "Sd", host, (int)port);
} else {
*cmd_len = REDIS_SPPRINTF(cmd, kw, "ss", ZEND_STRL("NO"), ZEND_STRL("ONE"));
}
return SUCCESS;
}
int
redis_zinterunion_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
zval *z_keys, *z_weights = NULL, *z_opts = NULL, *z_ele;
redisZcmdOptions opts = {0};
smart_string cmdstr = {0};
int numkeys, flags;
short s2 = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|a!a",
&z_keys, &z_weights, &z_opts) == FAILURE)
{
return FAILURE;
}
if ((numkeys = zend_hash_num_elements(Z_ARRVAL_P(z_keys))) == 0) {
return FAILURE;
}
if (z_weights && zend_hash_num_elements(Z_ARRVAL_P(z_weights)) != numkeys) {
php_error_docref(NULL, E_WARNING, "WEIGHTS and keys array should be the same size!");
return FAILURE;
}
flags = redis_get_zcmd_flags(kw);
redis_get_zcmd_options(&opts, z_opts, flags);
redis_cmd_init_sstr(&cmdstr, 1 + numkeys + (z_weights ? 1 + numkeys : 0) + (opts.aggregate ? 2 : 0) + opts.withscores, kw, strlen(kw));
redis_cmd_append_sstr_long(&cmdstr, numkeys);
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(z_keys), z_ele) {
ZVAL_DEREF(z_ele);
redis_cmd_append_sstr_key_zval(&cmdstr, z_ele, redis_sock, slot);
if (slot) {
if (s2 && s2 != *slot) {
php_error_docref(NULL, E_WARNING, "Not all keys hash to the same slot");
efree(cmdstr.c);
return FAILURE;
}
s2 = *slot;
}
} ZEND_HASH_FOREACH_END();
if (z_weights) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "WEIGHTS");
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(z_weights), z_ele) {
ZVAL_DEREF(z_ele);
if (redis_cmd_append_sstr_score(&cmdstr, z_ele) == FAILURE) {
efree(cmdstr.c);
return FAILURE;
}
} ZEND_HASH_FOREACH_END();
}
if (opts.aggregate) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "AGGREGATE");
redis_cmd_append_sstr_zstr(&cmdstr, opts.aggregate);
}
if (opts.withscores) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "WITHSCORES");
*ctx = PHPREDIS_CTX_PTR;
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
int
redis_zdiffstore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
smart_string cmdstr = {0};
zend_string *dst = NULL;
HashTable *keys = NULL;
zend_ulong nkeys;
short s2 = 0;
zval *zkey;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_STR(dst)
Z_PARAM_ARRAY_HT(keys)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
nkeys = zend_hash_num_elements(keys);
if (nkeys == 0)
return FAILURE;
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 2 + nkeys, "ZDIFFSTORE");
redis_cmd_append_sstr_key_zstr(&cmdstr, dst, redis_sock, slot);
redis_cmd_append_sstr_long(&cmdstr, nkeys);
ZEND_HASH_FOREACH_VAL(keys, zkey) {
ZVAL_DEREF(zkey);
redis_cmd_append_sstr_key_zval(&cmdstr, zkey, redis_sock, slot ? &s2 : NULL);
if (slot && *slot != s2) {
php_error_docref(NULL, E_WARNING, "All keys must hash to the same slot");
efree(cmdstr.c);
return FAILURE;
}
} ZEND_HASH_FOREACH_END();
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* ZUNIONSTORE, ZINTERSTORE */
int
redis_zinterunionstore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
HashTable *keys = NULL, *weights = NULL;
smart_string cmdstr = {0};
zend_string *dst = NULL;
zend_string *agg = NULL;
zend_ulong nkeys;
zval *zv = NULL;
short s2 = 0;
ZEND_PARSE_PARAMETERS_START(2, 4)
Z_PARAM_STR(dst)
Z_PARAM_ARRAY_HT(keys)
Z_PARAM_OPTIONAL
Z_PARAM_ARRAY_HT_OR_NULL(weights)
Z_PARAM_STR_OR_NULL(agg)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
nkeys = zend_hash_num_elements(keys);
if (nkeys == 0)
return FAILURE;
if (weights != NULL && zend_hash_num_elements(weights) != nkeys) {
php_error_docref(NULL, E_WARNING, "WEIGHTS and keys array must be the same size!");
return FAILURE;
}
// AGGREGATE option
if (agg != NULL && (!zend_string_equals_literal_ci(agg, "SUM") &&
!zend_string_equals_literal_ci(agg, "MIN") &&
!zend_string_equals_literal_ci(agg, "MAX")))
{
php_error_docref(NULL, E_WARNING, "AGGREGATE option must be 'SUM', 'MIN', or 'MAX'");
return FAILURE;
}
redis_cmd_init_sstr(&cmdstr, 2 + nkeys + (weights ? 1 + nkeys : 0) + (agg ? 2 : 0), kw, strlen(kw));
redis_cmd_append_sstr_key_zstr(&cmdstr, dst, redis_sock, slot);
redis_cmd_append_sstr_int(&cmdstr, nkeys);
ZEND_HASH_FOREACH_VAL(keys, zv) {
ZVAL_DEREF(zv);
redis_cmd_append_sstr_key_zval(&cmdstr, zv, redis_sock, slot ? &s2 : NULL);
if (slot && s2 != *slot) {
php_error_docref(NULL, E_WARNING, "All keys don't hash to the same slot!");
efree(cmdstr.c);
return FAILURE;
}
} ZEND_HASH_FOREACH_END();
if (weights) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "WEIGHTS");
ZEND_HASH_FOREACH_VAL(weights, zv) {
ZVAL_DEREF(zv);
if (redis_cmd_append_sstr_score(&cmdstr, zv) == FAILURE) {
efree(cmdstr.c);
return FAILURE;
}
} ZEND_HASH_FOREACH_END();
}
if (agg) {
redis_cmd_append_sstr(&cmdstr, ZEND_STRL("AGGREGATE"));
redis_cmd_append_sstr_zstr(&cmdstr, agg);
}
// Push out values
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
int redis_pubsub_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
HashTable *channels = NULL;
smart_string cmdstr = {0};
zend_string *op, *pattern = NULL;
zval *arg = NULL, *z_chan;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_STR(op)
Z_PARAM_OPTIONAL
Z_PARAM_ZVAL(arg)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
if (zend_string_equals_literal_ci(op, "NUMPAT")) {
*ctx = NULL;
} else if (zend_string_equals_literal_ci(op, "CHANNELS") ||
zend_string_equals_literal_ci(op, "SHARDCHANNELS")
) {
if (arg != NULL) {
if (Z_TYPE_P(arg) != IS_STRING) {
php_error_docref(NULL, E_WARNING, "Invalid patern value");
return FAILURE;
}
pattern = zval_get_string(arg);
}
*ctx = PHPREDIS_CTX_PTR;
} else if (zend_string_equals_literal_ci(op, "NUMSUB") ||
zend_string_equals_literal_ci(op, "SHARDNUMSUB")
) {
if (arg != NULL) {
if (Z_TYPE_P(arg) != IS_ARRAY) {
php_error_docref(NULL, E_WARNING, "Invalid channels value");
return FAILURE;
}
channels = Z_ARRVAL_P(arg);
}
*ctx = PHPREDIS_CTX_PTR + 1;
} else {
php_error_docref(NULL, E_WARNING, "Unknown PUBSUB operation '%s'", ZSTR_VAL(op));
return FAILURE;
}
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 1 + !!pattern + (channels ? zend_hash_num_elements(channels) : 0), "PUBSUB");
redis_cmd_append_sstr_zstr(&cmdstr, op);
if (pattern != NULL) {
redis_cmd_append_sstr_zstr(&cmdstr, pattern);
zend_string_release(pattern);
} else if (channels != NULL) {
ZEND_HASH_FOREACH_VAL(channels, z_chan) {
redis_cmd_append_sstr_key_zval(&cmdstr, z_chan, redis_sock, slot);
} ZEND_HASH_FOREACH_END();
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* SUBSCRIBE/PSUBSCRIBE/SSUBSCRIBE */
int redis_subscribe_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
zval *z_arr, *z_chan;
HashTable *ht_chan;
smart_string cmdstr = {0};
subscribeContext *sctx = ecalloc(1, sizeof(*sctx));
unsigned short shardslot = REDIS_CLUSTER_SLOTS;
short s2;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "af", &z_arr,
&sctx->cb.fci, &sctx->cb.fci_cache) == FAILURE)
{
efree(sctx);
return FAILURE;
}
ht_chan = Z_ARRVAL_P(z_arr);
sctx->kw = kw;
sctx->argc = zend_hash_num_elements(ht_chan);
if (sctx->argc == 0) {
efree(sctx);
return FAILURE;
}
if (strcasecmp(kw, "ssubscribe") == 0) {
zend_hash_internal_pointer_reset(ht_chan);
if ((z_chan = zend_hash_get_current_data(ht_chan)) == NULL) {
php_error_docref(NULL, E_WARNING, "Internal Zend HashTable error");
efree(sctx);
return FAILURE;
}
shardslot = cluster_hash_key_zval(z_chan);
}
// Start command construction
redis_cmd_init_sstr(&cmdstr, sctx->argc, kw, strlen(kw));
// Iterate over channels
ZEND_HASH_FOREACH_VAL(ht_chan, z_chan) {
redis_cmd_append_sstr_key_zval(&cmdstr, z_chan, redis_sock, slot ? &s2 : NULL);
if (slot && (shardslot != REDIS_CLUSTER_SLOTS && s2 != shardslot)) {
php_error_docref(NULL, E_WARNING, "All shard channels needs to belong to a single slot");
smart_string_free(&cmdstr);
efree(sctx);
return FAILURE;
}
} ZEND_HASH_FOREACH_END();
// Push values out
*cmd_len = cmdstr.len;
*cmd = cmdstr.c;
*ctx = (void*)sctx;
if (shardslot != REDIS_CLUSTER_SLOTS) {
if (slot) *slot = shardslot;
} else {
// Pick a slot at random
CMD_RAND_SLOT(slot);
}
return SUCCESS;
}
/* UNSUBSCRIBE/PUNSUBSCRIBE/SUNSUBSCRIBE */
int redis_unsubscribe_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
smart_string cmdstr = {0};
subscribeContext *sctx;
HashTable *channels;
zval *channel;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ARRAY_HT(channels)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
if (zend_hash_num_elements(channels) == 0)
return FAILURE;
sctx = ecalloc(1, sizeof(*sctx));
sctx->kw = kw;
sctx->argc = zend_hash_num_elements(channels);
redis_cmd_init_sstr(&cmdstr, sctx->argc, kw, strlen(kw));
ZEND_HASH_FOREACH_VAL(channels, channel) {
redis_cmd_append_sstr_key_zval(&cmdstr, channel, redis_sock, slot);
} ZEND_HASH_FOREACH_END();
*cmd_len = cmdstr.len;
*cmd = cmdstr.c;
*ctx = sctx;
return SUCCESS;
}
/* ZRANGEBYLEX/ZREVRANGEBYLEX */
int redis_zrangebylex_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
char *key, *min, *max;
size_t key_len, min_len, max_len;
int argc = ZEND_NUM_ARGS();
zend_long offset, count;
/* We need either 3 or 5 arguments for this to be valid */
if (argc != 3 && argc != 5) {
php_error_docref(0, E_WARNING, "Must pass either 3 or 5 arguments");
return FAILURE;
}
if (zend_parse_parameters(argc, "sss|ll", &key, &key_len, &min, &min_len,
&max, &max_len, &offset, &count) == FAILURE)
{
return FAILURE;
}
/* min and max must start with '(' or '[', or be either '-' or '+' */
if (!validate_zlex_arg(min, min_len) || !validate_zlex_arg(max, max_len)) {
php_error_docref(NULL, E_WARNING,
"Min/Max args can be '-' or '+', or start with '[' or '('");
return FAILURE;
}
/* Construct command */
if (argc == 3) {
*cmd_len = REDIS_CMD_SPPRINTF(cmd, kw, "kss", key, key_len, min, min_len,
max, max_len);
} else {
*cmd_len = REDIS_CMD_SPPRINTF(cmd, kw, "ksssll", key, key_len, min, min_len,
max, max_len, "LIMIT", 5, offset, count);
}
return SUCCESS;
}
/* ZLEXCOUNT/ZREMRANGEBYLEX */
int redis_gen_zlex_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
char *key, *min, *max;
size_t key_len, min_len, max_len;
/* Parse args */
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss", &key, &key_len,
&min, &min_len, &max, &max_len) == FAILURE)
{
return FAILURE;
}
/* Quick sanity check on min/max */
if (!validate_zlex_arg(min, min_len) || !validate_zlex_arg(max, max_len)) {
php_error_docref(NULL, E_WARNING,
"Min/Max args can be '-' or '+', or start with '[' or '('");
return FAILURE;
}
/* Construct command */
*cmd_len = REDIS_CMD_SPPRINTF(cmd, kw, "kss", key, key_len, min, min_len,
max, max_len);
return SUCCESS;
}
/* EVAL and EVALSHA */
int redis_eval_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, char *kw,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
char *lua;
int argc = 0;
zval *z_arr = NULL, *z_ele;
HashTable *ht_arr;
zend_long num_keys = 0;
smart_string cmdstr = {0};
size_t lua_len;
zend_string *zstr;
short prevslot = -1;
/* Parse args */
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|al", &lua, &lua_len,
&z_arr, &num_keys) == FAILURE)
{
return FAILURE;
}
/* Grab arg count */
if (z_arr != NULL) {
ht_arr = Z_ARRVAL_P(z_arr);
argc = zend_hash_num_elements(ht_arr);
}
/* EVAL[SHA] {script || sha1} {num keys} */
redis_cmd_init_sstr(&cmdstr, 2 + argc, kw, strlen(kw));
redis_cmd_append_sstr(&cmdstr, lua, lua_len);
redis_cmd_append_sstr_long(&cmdstr, num_keys);
// Iterate over our args if we have any
if (argc > 0) {
ZEND_HASH_FOREACH_VAL(ht_arr, z_ele) {
zstr = zval_get_string(z_ele);
/* If we're still on a key, prefix it check slot */
if (num_keys-- > 0) {
redis_cmd_append_sstr_key(&cmdstr, ZSTR_VAL(zstr), ZSTR_LEN(zstr), redis_sock, slot);
/* If we have been passed a slot, all keys must match */
if (slot) {
if (prevslot != -1 && prevslot != *slot) {
zend_string_release(zstr);
php_error_docref(0, E_WARNING, "All keys do not map to the same slot");
return FAILURE;
}
prevslot = *slot;
}
} else {
redis_cmd_append_sstr(&cmdstr, ZSTR_VAL(zstr), ZSTR_LEN(zstr));
}
zend_string_release(zstr);
} ZEND_HASH_FOREACH_END();
} else {
/* Any slot will do */
CMD_RAND_SLOT(slot);
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* Commands that take a key followed by a variable list of serializable
* values (RPUSH, LPUSH, SADD, SREM, etc...) */
int redis_key_varval_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
zval *z_args;
smart_string cmdstr = {0};
size_t i;
int argc = ZEND_NUM_ARGS();
// We at least need a key and one value
if (argc < 2) {
zend_wrong_param_count();
return FAILURE;
}
// Make sure we at least have a key, and we can get other args
z_args = emalloc(argc * sizeof(zval));
if (zend_get_parameters_array(ht, argc, z_args) == FAILURE) {
efree(z_args);
return FAILURE;
}
/* Initialize our command */
redis_cmd_init_sstr(&cmdstr, argc, kw, strlen(kw));
/* Append key */
zend_string *zstr = zval_get_string(&z_args[0]);
redis_cmd_append_sstr_key(&cmdstr, ZSTR_VAL(zstr), ZSTR_LEN(zstr), redis_sock, slot);
zend_string_release(zstr);
/* Add members */
for (i = 1; i < argc; i++ ){
redis_cmd_append_sstr_zval(&cmdstr, &z_args[i], redis_sock);
}
// Push out values
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
// Cleanup arg array
efree(z_args);
// Success!
return SUCCESS;
}
/* Commands that take a key and then an array of values */
static int gen_key_arr_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, zend_bool pack_values, char **cmd, int *cmd_len,
short *slot, void **ctx)
{
smart_string cmdstr = {0};
HashTable *values = NULL;
zend_string *key = NULL;
zval *zv;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_STR(key)
Z_PARAM_ARRAY_HT(values)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
if (zend_hash_num_elements(values) == 0)
return FAILURE;
redis_cmd_init_sstr(&cmdstr, 1 + zend_hash_num_elements(values), kw, strlen(kw));
redis_cmd_append_sstr_key_zstr(&cmdstr, key, redis_sock, slot);
ZEND_HASH_FOREACH_VAL(values, zv) {
redis_cmd_append_sstr_zval(&cmdstr, zv, pack_values ? redis_sock : NULL);
} ZEND_HASH_FOREACH_END();
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
int redis_key_val_arr_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
return gen_key_arr_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, kw,
1, cmd, cmd_len, slot, ctx);
}
int redis_key_str_arr_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
return gen_key_arr_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, kw,
0, cmd, cmd_len, slot, ctx);
}
/* Generic function that takes one or more non-serialized arguments */
static int
gen_vararg_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
uint32_t min_argc, char *kw, char **cmd, int *cmd_len,
short *slot, void **ctx)
{
smart_string cmdstr = {0};
zval *argv = NULL;
int argc = 0;
uint32_t i;
ZEND_PARSE_PARAMETERS_START(min_argc, -1)
Z_PARAM_VARIADIC('*', argv, argc)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
redis_cmd_init_sstr(&cmdstr, argc, kw, strlen(kw));
for (i = 0; i < argc; i++) {
redis_cmd_append_sstr_zval(&cmdstr, &argv[i], NULL);
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
int redis_mset_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
smart_string cmdstr = {0};
HashTable *kvals = NULL;
zend_string *key;
zend_ulong idx;
zval *zv;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ARRAY_HT(kvals)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
if (zend_hash_num_elements(kvals) == 0)
return FAILURE;
redis_cmd_init_sstr(&cmdstr, zend_hash_num_elements(kvals) * 2, kw, strlen(kw));
ZEND_HASH_FOREACH_KEY_VAL(kvals, idx, key, zv) {
ZVAL_DEREF(zv);
if (key) {
redis_cmd_append_sstr_key_zstr(&cmdstr, key, redis_sock, NULL);
} else {
redis_cmd_append_sstr_key_long(&cmdstr, idx, redis_sock, NULL);
}
redis_cmd_append_sstr_zval(&cmdstr, zv, redis_sock);
} ZEND_HASH_FOREACH_END();
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* Generic function that takes a variable number of keys, with an optional
* timeout value. This can handle various SUNION/SUNIONSTORE/BRPOP type
* commands. */
static int gen_varkey_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, int kw_len, zend_bool has_timeout,
char **cmd, int *cmd_len, short *slot)
{
zval *argv = NULL, ztimeout = {0}, *zv;
smart_string cmdstr = {0};
uint32_t min_argc;
short kslot = -1;
int single_array;
int argc = 0;
min_argc = has_timeout ? 2 : 1;
ZEND_PARSE_PARAMETERS_START(min_argc, -1)
Z_PARAM_VARIADIC('*', argv, argc)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
single_array = argc == min_argc && Z_TYPE(argv[0]) == IS_ARRAY;
if (has_timeout) {
if (single_array)
ZVAL_COPY_VALUE(&ztimeout, &argv[1]);
else
ZVAL_COPY_VALUE(&ztimeout, &argv[argc - 1]);
if (Z_TYPE(ztimeout) != IS_LONG && Z_TYPE(ztimeout) != IS_DOUBLE) {
php_error_docref(NULL, E_WARNING, "Timeout must be a long or double");
return FAILURE;
}
}
// If we're running a single array, rework args
if (single_array) {
/* Need at least one argument */
argc = zend_hash_num_elements(Z_ARRVAL(argv[0]));
if (argc == 0)
return FAILURE;
if (has_timeout) argc++;
}
// Begin construction of our command
redis_cmd_init_sstr(&cmdstr, argc, kw, kw_len);
if (single_array) {
ZEND_HASH_FOREACH_VAL(Z_ARRVAL(argv[0]), zv) {
redis_cmd_append_sstr_key_zval(&cmdstr, zv, redis_sock, slot);
if (slot) {
if (kslot != -1 && *slot != kslot)
goto cross_slot;
kslot = *slot;
}
} ZEND_HASH_FOREACH_END();
} else {
uint32_t i;
for(i = 0; i < argc - !!has_timeout; i++) {
redis_cmd_append_sstr_key_zval(&cmdstr, &argv[i], redis_sock, slot);
if (slot) {
if (kslot != -1 && *slot != kslot)
goto cross_slot;
kslot = *slot;
}
}
}
if (Z_TYPE(ztimeout) == IS_DOUBLE) {
redis_cmd_append_sstr_dbl(&cmdstr, Z_DVAL(ztimeout));
} else if (Z_TYPE(ztimeout) == IS_LONG) {
redis_cmd_append_sstr_long(&cmdstr, Z_LVAL(ztimeout));
}
// Push out parameters
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
cross_slot:
efree(cmdstr.c);
php_error_docref(NULL, E_WARNING, "Not all keys hash to the same slot!");
return FAILURE;
}
int redis_mpop_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, char *kw,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
int argc, blocking, is_zmpop;
smart_string cmdstr = {0};
zend_string *from = NULL;
HashTable *keys = NULL;
double timeout = 0.0;
zend_long count = 1;
short slot2 = -1;
zval *zv;
/* Sanity check on our keyword */
ZEND_ASSERT(kw != NULL && *kw != '\0' && *(kw+1) != '\0');
blocking = tolower(*kw) == 'b';
is_zmpop = tolower(kw[blocking]) == 'z';
ZEND_PARSE_PARAMETERS_START(2 + blocking, 3 + blocking) {
if (blocking) {
Z_PARAM_DOUBLE(timeout)
}
Z_PARAM_ARRAY_HT(keys)
Z_PARAM_STR(from);
Z_PARAM_OPTIONAL
Z_PARAM_LONG(count);
} ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
if (zend_hash_num_elements(keys) == 0) {
php_error_docref(NULL, E_WARNING, "Must pass at least one key");
return FAILURE;
} else if (count < 1) {
php_error_docref(NULL, E_WARNING, "Count must be > 0");
return FAILURE;
} else if (!is_zmpop && !(zend_string_equals_literal_ci(from, "LEFT") ||
zend_string_equals_literal_ci(from, "RIGHT")))
{
php_error_docref(NULL, E_WARNING, "from must be either 'LEFT' or 'RIGHT'");
return FAILURE;
} else if (is_zmpop && !(zend_string_equals_literal_ci(from, "MIN") ||
zend_string_equals_literal_ci(from, "MAX")))
{
php_error_docref(NULL, E_WARNING, "from must be either 'MIN' or 'MAX'");
return FAILURE;
}
argc = 2 + !!blocking + zend_hash_num_elements(keys) + (count != 1 ? 2 : 0);
redis_cmd_init_sstr(&cmdstr, argc, kw, strlen(kw));
if (blocking) redis_cmd_append_sstr_dbl(&cmdstr, timeout);
redis_cmd_append_sstr_long(&cmdstr, zend_hash_num_elements(keys));
if (slot) *slot = -1;
ZEND_HASH_FOREACH_VAL(keys, zv) {
redis_cmd_append_sstr_key_zval(&cmdstr, zv, redis_sock, slot);
if (slot) {
if (slot2 != -1 && *slot != slot2) {
php_error_docref(NULL, E_WARNING, "All keys don't hash to the same slot");
efree(cmdstr.c);
return FAILURE;
}
slot2 = *slot;
}
} ZEND_HASH_FOREACH_END();
redis_cmd_append_sstr_zstr(&cmdstr, from);
if (count != 1) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "COUNT");
redis_cmd_append_sstr_long(&cmdstr, count);
}
*ctx = is_zmpop ? PHPREDIS_CTX_PTR : NULL;
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
int redis_info_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
return gen_vararg_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, 0,
"INFO", cmd, cmd_len, slot, ctx);
}
int redis_script_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
return gen_vararg_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, 1,
"SCRIPT", cmd, cmd_len, slot, ctx);
}
/* Generic handling of every blocking pop command (BLPOP, BZPOP[MIN/MAX], etc */
int redis_blocking_pop_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
return gen_varkey_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, kw,
strlen(kw), 1, cmd, cmd_len, slot);
}
/*
* Commands with specific signatures or that need unique functions because they
* have specific processing (argument validation, etc) that make them unique
*/
int
redis_pop_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx)
{
char *key;
size_t key_len;
smart_string cmdstr = {0};
zend_long count = 0;
// Make sure the function is being called correctly
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l",
&key, &key_len, &count) == FAILURE)
{
return FAILURE;
}
redis_cmd_init_sstr(&cmdstr, 1 + (count > 0), kw, strlen(kw));
redis_cmd_append_sstr_key(&cmdstr, key, key_len, redis_sock, slot);
if (count > 0) {
redis_cmd_append_sstr_long(&cmdstr, (long)count);
*ctx = PHPREDIS_CTX_PTR;
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
int
redis_acl_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
smart_string cmdstr = {0};
zend_string *op, *zstr;
zval *z_args = NULL;
int argc = 0, i;
ZEND_PARSE_PARAMETERS_START(1, -1)
Z_PARAM_STR(op)
Z_PARAM_OPTIONAL
Z_PARAM_VARIADIC('*', z_args, argc)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
if (zend_string_equals_literal_ci(op, "CAT") ||
zend_string_equals_literal_ci(op, "LIST") ||
zend_string_equals_literal_ci(op, "USERS")
) {
*ctx = NULL;
} else if (zend_string_equals_literal_ci(op, "LOAD") ||
zend_string_equals_literal_ci(op, "SAVE")
) {
*ctx = PHPREDIS_CTX_PTR;
} else if (zend_string_equals_literal_ci(op, "GENPASS") ||
zend_string_equals_literal_ci(op, "WHOAMI")
) {
*ctx = PHPREDIS_CTX_PTR + 1;
} else if (zend_string_equals_literal_ci(op, "SETUSER")) {
if (argc < 1) {
php_error_docref(NULL, E_WARNING, "ACL SETUSER requires at least one argument");
return FAILURE;
}
*ctx = PHPREDIS_CTX_PTR;
} else if (zend_string_equals_literal_ci(op, "DELUSER")) {
if (argc < 1) {
php_error_docref(NULL, E_WARNING, "ACL DELUSER requires at least one argument");
return FAILURE;
}
*ctx = PHPREDIS_CTX_PTR + 2;
} else if (zend_string_equals_literal_ci(op, "GETUSER")) {
if (argc < 1) {
php_error_docref(NULL, E_WARNING, "ACL GETUSER requires at least one argument");
return FAILURE;
}
*ctx = PHPREDIS_CTX_PTR + 3;
} else if (zend_string_equals_literal_ci(op, "DRYRUN")) {
if (argc < 2) {
php_error_docref(NULL, E_WARNING, "ACL DRYRUN requires at least two arguments");
return FAILURE;
}
*ctx = PHPREDIS_CTX_PTR;
} else if (zend_string_equals_literal_ci(op, "LOG")) {
if (argc > 0 && Z_TYPE(z_args[0]) == IS_STRING && ZVAL_STRICMP_STATIC(&z_args[0], "RESET")) {
*ctx = PHPREDIS_CTX_PTR;
} else {
*ctx = PHPREDIS_CTX_PTR + 4;
}
} else {
php_error_docref(NULL, E_WARNING, "Unknown ACL operation '%s'", ZSTR_VAL(op));
return FAILURE;
}
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 1 + argc, "ACL");
redis_cmd_append_sstr_zstr(&cmdstr, op);
for (i = 0; i < argc; ++i) {
zstr = zval_get_string(&z_args[i]);
redis_cmd_append_sstr_zstr(&cmdstr, zstr);
zend_string_release(zstr);
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* Attempt to pull a long expiry from a zval. We're more restrictave than zval_get_long
* because that function will return integers from things like open file descriptors
* which should simply fail as a TTL */
static int redis_try_get_expiry(zval *zv, zend_long *lval) {
double dval;
/* Success on an actual long or double */
if (Z_TYPE_P(zv) == IS_LONG || Z_TYPE_P(zv) == IS_DOUBLE) {
*lval = zval_get_long(zv);
return SUCCESS;
}
/* Automatically fail if we're not a string */
if (Z_TYPE_P(zv) != IS_STRING)
return FAILURE;
/* Attempt to get a long from the string */
switch (is_numeric_string(Z_STRVAL_P(zv), Z_STRLEN_P(zv), lval, &dval, 0)) {
case IS_DOUBLE:
*lval = dval;
REDIS_FALLTHROUGH;
case IS_LONG:
return SUCCESS;
default:
return FAILURE;
}
}
/* SET */
int redis_set_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
smart_string cmdstr = {0};
zval *z_value, *z_opts=NULL;
char *key = NULL, *exp_type = NULL, *set_type = NULL;
long exp_set = 0, keep_ttl = 0;
zend_long expire = -1;
zend_bool get = 0;
size_t key_len;
// Make sure the function is being called correctly
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz|z", &key, &key_len,
&z_value, &z_opts) == FAILURE)
{
return FAILURE;
}
// Check for an options array
if (z_opts && Z_TYPE_P(z_opts) == IS_ARRAY) {
HashTable *kt = Z_ARRVAL_P(z_opts);
zend_string *zkey;
zval *v;
/* Iterate our option array */
ZEND_HASH_FOREACH_STR_KEY_VAL(kt, zkey, v) {
ZVAL_DEREF(v);
/* Detect PX or EX argument and validate timeout */
if (zkey && (zend_string_equals_literal_ci(zkey, "EX") ||
zend_string_equals_literal_ci(zkey, "PX") ||
zend_string_equals_literal_ci(zkey, "EXAT") ||
zend_string_equals_literal_ci(zkey, "PXAT"))
) {
exp_set = 1;
/* Set expire type */
exp_type = ZSTR_VAL(zkey);
/* Try to extract timeout */
if (Z_TYPE_P(v) == IS_LONG) {
expire = Z_LVAL_P(v);
} else if (Z_TYPE_P(v) == IS_STRING) {
expire = atol(Z_STRVAL_P(v));
}
} else if (Z_TYPE_P(v) == IS_STRING) {
if (zend_string_equals_literal_ci(Z_STR_P(v), "KEEPTTL")) {
keep_ttl = 1;
} else if (zend_string_equals_literal_ci(Z_STR_P(v), "GET")) {
get = 1;
} else if (zend_string_equals_literal_ci(Z_STR_P(v), "NX") ||
zend_string_equals_literal_ci(Z_STR_P(v), "XX"))
{
set_type = Z_STRVAL_P(v);
}
}
} ZEND_HASH_FOREACH_END();
} else if (z_opts && Z_TYPE_P(z_opts) != IS_NULL) {
if (redis_try_get_expiry(z_opts, &expire) == FAILURE) {
php_error_docref(NULL, E_WARNING, "Expire must be a long, double, or a numeric string");
return FAILURE;
}
exp_set = 1;
}
/* Protect the user from syntax errors but give them some info about what's wrong */
if (exp_set && expire < 1) {
php_error_docref(NULL, E_WARNING, "EXPIRE can't be < 1");
return FAILURE;
} else if (exp_type && keep_ttl) {
php_error_docref(NULL, E_WARNING, "KEEPTTL can't be combined with EX or PX option");
return FAILURE;
}
/* Backward compatibility: If we are passed no options except an EXPIRE ttl, we
* actually execute a SETEX command */
if (expire > 0 && !exp_type && !set_type && !keep_ttl) {
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "SETEX", "klv", key, key_len, expire, z_value);
return SUCCESS;
}
/* Calculate argc based on options set */
int argc = 2 + (exp_type ? 2 : 0) + (set_type != NULL) + (keep_ttl != 0) + get;
/* Initial SET */
redis_cmd_init_sstr(&cmdstr, argc, "SET", 3);
redis_cmd_append_sstr_key(&cmdstr, key, key_len, redis_sock, slot);
redis_cmd_append_sstr_zval(&cmdstr, z_value, redis_sock);
if (exp_type) {
redis_cmd_append_sstr(&cmdstr, exp_type, strlen(exp_type));
redis_cmd_append_sstr_long(&cmdstr, (long)expire);
}
if (set_type)
redis_cmd_append_sstr(&cmdstr, set_type, strlen(set_type));
if (keep_ttl)
redis_cmd_append_sstr(&cmdstr, "KEEPTTL", 7);
if (get) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "GET");
*ctx = PHPREDIS_CTX_PTR;
}
/* Push command and length to the caller */
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* MGET */
int redis_mget_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
smart_string cmdstr = {0};
HashTable *keys = NULL;
zval *zkey;
/* RedisCluster has a custom MGET implementation */
ZEND_ASSERT(slot == NULL);
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ARRAY_HT(keys)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
if (zend_hash_num_elements(keys) == 0)
return FAILURE;
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, zend_hash_num_elements(keys), "MGET");
ZEND_HASH_FOREACH_VAL(keys, zkey) {
ZVAL_DEREF(zkey);
redis_cmd_append_sstr_key_zval(&cmdstr, zkey, redis_sock, slot);
} ZEND_HASH_FOREACH_END();
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
int
redis_getex_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
smart_string cmdstr = {0};
char *key, *exp_type = NULL;
zval *z_opts = NULL, *z_ele;
zend_long expire = -1;
zend_bool persist = 0;
zend_string *zkey;
size_t key_len;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|a",
&key, &key_len, &z_opts) == FAILURE)
{
return FAILURE;
}
if (z_opts != NULL) {
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(z_opts), zkey, z_ele) {
if (zkey != NULL) {
ZVAL_DEREF(z_ele);
if (ZSTR_STRICMP_STATIC(zkey, "EX") ||
ZSTR_STRICMP_STATIC(zkey, "PX") ||
ZSTR_STRICMP_STATIC(zkey, "EXAT") ||
ZSTR_STRICMP_STATIC(zkey, "PXAT")
) {
exp_type = ZSTR_VAL(zkey);
expire = zval_get_long(z_ele);
persist = 0;
} else if (ZSTR_STRICMP_STATIC(zkey, "PERSIST")) {
persist = zval_is_true(z_ele);
exp_type = NULL;
}
}
} ZEND_HASH_FOREACH_END();
}
if (exp_type != NULL && expire < 1) {
php_error_docref(NULL, E_WARNING, "EXPIRE can't be < 1");
return FAILURE;
}
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 1 + (exp_type ? 2 : persist), "GETEX");
redis_cmd_append_sstr_key(&cmdstr, key, key_len, redis_sock, slot);
if (exp_type != NULL) {
redis_cmd_append_sstr(&cmdstr, exp_type, strlen(exp_type));
redis_cmd_append_sstr_long(&cmdstr, expire);
} else if (persist) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "PERSIST");
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* BRPOPLPUSH */
int redis_brpoplpush_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
zend_string *src = NULL, *dst = NULL;
double timeout = 0;
ZEND_PARSE_PARAMETERS_START(3, 3)
Z_PARAM_STR(src)
Z_PARAM_STR(dst)
Z_PARAM_DOUBLE(timeout)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
src = redis_key_prefix_zstr(redis_sock, src);
dst = redis_key_prefix_zstr(redis_sock, dst);
if (slot && (*slot = cluster_hash_key_zstr(src)) != cluster_hash_key_zstr(dst)) {
php_error_docref(NULL, E_WARNING, "Keys must hash to the same slot");
zend_string_release(src);
zend_string_release(dst);
return FAILURE;
}
/* Consistency with Redis. If timeout < 0 use RPOPLPUSH */
if (timeout < 0) {
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "RPOPLPUSH", "SS", src, dst);
} else if (fabs(timeout - (long)timeout) < .0001) {
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "BRPOPLPUSH", "SSd", src, dst, (long)timeout);
} else {
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "BRPOPLPUSH", "SSf", src, dst, timeout);
}
zend_string_release(src);
zend_string_release(dst);
return SUCCESS;
}
/* To maintain backward compatibility with earlier versions of phpredis, we
* allow for an optional "increment by" argument for INCR and DECR even though
* that's not how Redis proper works */
#define TYPE_INCR 0
#define TYPE_DECR 1
/* Handle INCR(BY) and DECR(BY) depending on optional increment value */
static int
redis_atomic_increment(INTERNAL_FUNCTION_PARAMETERS, int type,
RedisSock *redis_sock, char **cmd, int *cmd_len,
short *slot, void **ctx)
{
char *key;
size_t key_len;
zend_long val = 1;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &key, &key_len,
&val) == FAILURE)
{
return FAILURE;
}
/* If our value is 1 we use INCR/DECR. For other values, treat the call as
* an INCRBY or DECRBY call */
if (type == TYPE_INCR) {
if (val == 1) {
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "INCR", "k", key, key_len);
} else {
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "INCRBY", "kl", key, key_len, val);
}
} else {
if (val == 1) {
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "DECR", "k", key, key_len);
} else {
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "DECRBY", "kl", key, key_len, val);
}
}
/* Success */
return SUCCESS;
}
/* INCR */
int redis_incr_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
return redis_atomic_increment(INTERNAL_FUNCTION_PARAM_PASSTHRU,
TYPE_INCR, redis_sock, cmd, cmd_len, slot, ctx);
}
/* DECR */
int redis_decr_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
return redis_atomic_increment(INTERNAL_FUNCTION_PARAM_PASSTHRU,
TYPE_DECR, redis_sock, cmd, cmd_len, slot, ctx);
}
/* HINCRBY */
int redis_hincrby_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
char *key, *mem;
size_t key_len, mem_len;
zend_long byval;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssl", &key, &key_len,
&mem, &mem_len, &byval) == FAILURE)
{
return FAILURE;
}
// Construct command
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "HINCRBY", "ksl", key, key_len, mem, mem_len, byval);
// Success
return SUCCESS;
}
/* HINCRBYFLOAT */
int redis_hincrbyfloat_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
char *key, *mem;
size_t key_len, mem_len;
double byval;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssd", &key, &key_len,
&mem, &mem_len, &byval) == FAILURE)
{
return FAILURE;
}
// Construct command
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "HINCRBYFLOAT", "ksf", key, key_len, mem,
mem_len, byval);
// Success
return SUCCESS;
}
/* HMGET */
int redis_hmget_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
zval *field = NULL, *zctx = NULL;
smart_string cmdstr = {0};
HashTable *fields = NULL;
zend_string *key = NULL;
zend_ulong valid = 0, i;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_STR(key)
Z_PARAM_ARRAY_HT(fields)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
if (zend_hash_num_elements(fields) == 0)
return FAILURE;
zctx = ecalloc(1 + zend_hash_num_elements(fields), sizeof(*zctx));
ZEND_HASH_FOREACH_VAL(fields, field) {
ZVAL_DEREF(field);
if (!((Z_TYPE_P(field) == IS_STRING && Z_STRLEN_P(field) > 0) || Z_TYPE_P(field) == IS_LONG))
continue;
ZVAL_COPY(&zctx[valid++], field);
} ZEND_HASH_FOREACH_END();
if (valid == 0) {
efree(zctx);
return FAILURE;
}
ZVAL_NULL(&zctx[valid]);
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 1 + valid, "HMGET");
redis_cmd_append_sstr_key_zstr(&cmdstr, key, redis_sock, slot);
for (i = 0; i < valid; i++) {
redis_cmd_append_sstr_zval(&cmdstr, &zctx[i], NULL);
}
// Push out command, length, and key context
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
*ctx = zctx;
return SUCCESS;
}
/* HMSET */
int redis_hmset_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
smart_string cmdstr = {0};
zend_string *key = NULL;
HashTable *ht = NULL;
uint32_t fields;
zend_ulong idx;
zval *zv;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_STR(key)
Z_PARAM_ARRAY_HT(ht)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
fields = zend_hash_num_elements(ht);
if (fields == 0)
return FAILURE;
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 1 + (2 * fields), "HMSET");
redis_cmd_append_sstr_key_zstr(&cmdstr, key, redis_sock, slot);
ZEND_HASH_FOREACH_KEY_VAL(ht, idx, key, zv) {
if (key) {
redis_cmd_append_sstr_zstr(&cmdstr, key);
} else {
redis_cmd_append_sstr_long(&cmdstr, idx);
}
redis_cmd_append_sstr_zval(&cmdstr, zv, redis_sock);
} ZEND_HASH_FOREACH_END();
*cmd_len = cmdstr.len;
*cmd = cmdstr.c;
return SUCCESS;
}
/* HSTRLEN */
int
redis_hstrlen_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
char *key, *field;
size_t key_len, field_len;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &key, &key_len,
&field, &field_len) == FAILURE
) {
return FAILURE;
}
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "HSTRLEN", "ks", key, key_len, field, field_len);
return SUCCESS;
}
static void redis_get_lcs_options(redisLcsOptions *dst, HashTable *ht) {
zend_string *key;
zval *zv;
ZEND_ASSERT(dst != NULL);
memset(dst, 0, sizeof(*dst));
if (ht == NULL)
return;
ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, zv) {
if (key) {
if (zend_string_equals_literal_ci(key, "LEN")) {
dst->idx = 0;
dst->len = zval_is_true(zv);
} else if (zend_string_equals_literal_ci(key, "IDX")) {
dst->len = 0;
dst->idx = zval_is_true(zv);
} else if (zend_string_equals_literal_ci(key, "MINMATCHLEN")) {
dst->minmatchlen = zval_get_long(zv);
} else if (zend_string_equals_literal_ci(key, "WITHMATCHLEN")) {
dst->withmatchlen = zval_is_true(zv);
} else {
php_error_docref(NULL, E_WARNING, "Unknown LCS option '%s'", ZSTR_VAL(key));
}
} else if (Z_TYPE_P(zv) == IS_STRING) {
if (zend_string_equals_literal_ci(Z_STR_P(zv), "LEN")) {
dst->idx = 0;
dst->len = 1;
} else if (zend_string_equals_literal_ci(Z_STR_P(zv), "IDX")) {
dst->idx = 1;
dst->len = 0;
} else if (zend_string_equals_literal_ci(Z_STR_P(zv), "WITHMATCHLEN")) {
dst->withmatchlen = 1;
}
}
} ZEND_HASH_FOREACH_END();
}
/* LCS */
int redis_lcs_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
zend_string *key1 = NULL, *key2 = NULL;
smart_string cmdstr = {0};
HashTable *ht = NULL;
redisLcsOptions opt;
int argc;
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STR(key1)
Z_PARAM_STR(key2)
Z_PARAM_OPTIONAL
Z_PARAM_ARRAY_HT_OR_NULL(ht)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
key1 = redis_key_prefix_zstr(redis_sock, key1);
key2 = redis_key_prefix_zstr(redis_sock, key2);
if (slot) {
*slot = cluster_hash_key_zstr(key1);
if (*slot != cluster_hash_key_zstr(key2)) {
php_error_docref(NULL, E_WARNING, "Warning, not all keys hash to the same slot!");
zend_string_release(key1);
zend_string_release(key2);
return FAILURE;
}
}
redis_get_lcs_options(&opt, ht);
argc = 2 + !!opt.idx + !!opt.len + !!opt.withmatchlen + (opt.minmatchlen ? 2 : 0);
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc, "LCS");
redis_cmd_append_sstr_zstr(&cmdstr, key1);
redis_cmd_append_sstr_zstr(&cmdstr, key2);
REDIS_CMD_APPEND_SSTR_OPT_STATIC(&cmdstr, opt.idx, "IDX");
REDIS_CMD_APPEND_SSTR_OPT_STATIC(&cmdstr, opt.len, "LEN");
REDIS_CMD_APPEND_SSTR_OPT_STATIC(&cmdstr, opt.withmatchlen, "WITHMATCHLEN");
if (opt.minmatchlen) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "MINMATCHLEN");
redis_cmd_append_sstr_long(&cmdstr, opt.minmatchlen);
}
zend_string_release(key1);
zend_string_release(key2);
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
int redis_slowlog_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
enum {SLOWLOG_GET, SLOWLOG_LEN, SLOWLOG_RESET} mode;
smart_string cmdstr = {0};
zend_string *op = NULL;
zend_long arg = 0;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_STR(op)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(arg)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
if (zend_string_equals_literal_ci(op, "GET")) {
mode = SLOWLOG_GET;
} else if (zend_string_equals_literal_ci(op, "LEN")) {
mode = SLOWLOG_LEN;
} else if (zend_string_equals_literal_ci(op, "RESET")) {
mode = SLOWLOG_RESET;
} else {
php_error_docref(NULL, E_WARNING, "Unknown SLOWLOG operation '%s'", ZSTR_VAL(op));
return FAILURE;
}
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 1 + (mode == SLOWLOG_GET && ZEND_NUM_ARGS() == 2), "SLOWLOG");
redis_cmd_append_sstr_zstr(&cmdstr, op);
if (mode == SLOWLOG_GET && ZEND_NUM_ARGS() == 2)
redis_cmd_append_sstr_long(&cmdstr, arg);
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
void redis_get_restore_options(redisRestoreOptions *dst, HashTable *ht) {
zend_string *key;
zend_long lval;
zval *zv;
ZEND_ASSERT(dst != NULL);
memset(dst, 0, sizeof(*dst));
dst->idletime = dst->freq = -1;
if (ht == NULL)
return;
ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, zv) {
ZVAL_DEREF(zv);
if (key) {
if (zend_string_equals_literal_ci(key, "IDLETIME")) {
lval = zval_get_long(zv);
if (lval < 0) {
php_error_docref(NULL, E_WARNING, "IDLETIME must be >= 0");
} else {
dst->idletime = lval;
dst->freq = -1;
}
} else if (zend_string_equals_literal_ci(key, "FREQ")) {
lval = zval_get_long(zv);
if (lval < 0 || lval > 255) {
php_error_docref(NULL, E_WARNING, "FREQ must be >= 0 and <= 255");
} else {
dst->freq = lval;
dst->idletime = -1;
}
} else {
php_error_docref(NULL, E_WARNING, "Unknown RESTORE option '%s'", ZSTR_VAL(key));
}
} else if (Z_TYPE_P(zv) == IS_STRING) {
if (zend_string_equals_literal_ci(Z_STR_P(zv), "REPLACE")) {
dst->replace = 1;
} else if (zend_string_equals_literal_ci(Z_STR_P(zv), "ABSTTL")) {
dst->absttl = 1;
} else {
php_error_docref(NULL, E_WARNING, "Unknown RESTORE option '%s'", Z_STRVAL_P(zv));
}
}
} ZEND_HASH_FOREACH_END();
}
/* RESTORE */
int redis_restore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
zend_string *key, *value = NULL;
smart_string cmdstr = {0};
HashTable *options = NULL;
redisRestoreOptions opt;
zend_long timeout = 0;
int argc;
ZEND_PARSE_PARAMETERS_START(3, 4) {
Z_PARAM_STR(key)
Z_PARAM_LONG(timeout)
Z_PARAM_STR(value)
Z_PARAM_OPTIONAL
Z_PARAM_ARRAY_HT_OR_NULL(options)
} ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
redis_get_restore_options(&opt, options);
argc = 3 + (opt.idletime>-1?2:0) + (opt.freq>-1?2:0) + !!opt.absttl + !!opt.replace;
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc, "RESTORE");
redis_cmd_append_sstr_key(&cmdstr, ZSTR_VAL(key), ZSTR_LEN(key), redis_sock, slot);
redis_cmd_append_sstr_long(&cmdstr, timeout);
redis_cmd_append_sstr_zstr(&cmdstr, value);
REDIS_CMD_APPEND_SSTR_OPT_STATIC(&cmdstr, opt.replace, "REPLACE");
REDIS_CMD_APPEND_SSTR_OPT_STATIC(&cmdstr, opt.absttl, "ABSTTL");
if (opt.idletime > -1) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "IDLETIME");
redis_cmd_append_sstr_long(&cmdstr, opt.idletime);
}
if (opt.freq > -1) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "FREQ");
redis_cmd_append_sstr_long(&cmdstr, opt.freq);
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* BITPOS key bit [start [end [BYTE | BIT]]] */
int redis_bitpos_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
zend_long start = 0, end = -1;
zend_bool bit = 0, bybit = 0;
smart_string cmdstr = {0};
zend_string *key = NULL;
ZEND_PARSE_PARAMETERS_START(2, 5)
Z_PARAM_STR(key)
Z_PARAM_BOOL(bit)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(start)
Z_PARAM_LONG(end)
Z_PARAM_BOOL(bybit)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 2 + (ZEND_NUM_ARGS() > 2 ? 2 : 0) + !!bybit, "BITPOS");
redis_cmd_append_sstr_key_zstr(&cmdstr, key, redis_sock, slot);
redis_cmd_append_sstr_long(&cmdstr, bit);
/* Start and length if we were passed either */
if (ZEND_NUM_ARGS() > 2) {
redis_cmd_append_sstr_long(&cmdstr, start);
redis_cmd_append_sstr_long(&cmdstr, end);
}
/* Finally, BIT or BYTE if we were passed that argument */
REDIS_CMD_APPEND_SSTR_OPT_STATIC(&cmdstr, !!bybit, "BIT");
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* BITOP */
int redis_bitop_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
zval *z_args;
int i, argc = ZEND_NUM_ARGS();
smart_string cmdstr = {0};
short s2;
// Allocate space for args, parse them as an array
z_args = emalloc(argc * sizeof(zval));
if (zend_get_parameters_array(ht, argc, z_args) == FAILURE ||
argc < 3 || Z_TYPE(z_args[0]) != IS_STRING)
{
efree(z_args);
return FAILURE;
}
// If we were passed a slot pointer, init to a sentinel value
if (slot) *slot = -1;
// Initialize command construction, add our operation argument
redis_cmd_init_sstr(&cmdstr, argc, ZEND_STRL("BITOP"));
redis_cmd_append_sstr(&cmdstr, Z_STRVAL(z_args[0]), Z_STRLEN(z_args[0]));
// Now iterate over our keys argument
for (i = 1; i < argc; i++) {
// Append the key
redis_cmd_append_sstr_key_zval(&cmdstr, &z_args[i], redis_sock, slot ? &s2 : NULL);
// Verify slot if this is a Cluster request
if (slot) {
if (*slot != -1 && s2 != *slot) {
php_error_docref(NULL, E_WARNING, "Warning, not all keys hash to the same slot!");
efree(z_args);
efree(cmdstr.c);
return FAILURE;
}
*slot = s2;
}
}
// Free our argument array
efree(z_args);
// Push out variables
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* BITCOUNT */
int redis_bitcount_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
char *key;
size_t key_len;
zend_long start = 0, end = -1;
zend_bool isbit = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|llb", &key, &key_len,
&start, &end, &isbit) == FAILURE)
{
return FAILURE;
}
if (isbit) {
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "BITCOUNT", "kdds", key, key_len,
(int)start, (int)end, "BIT", 3);
} else {
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "BITCOUNT", "kdd", key, key_len,
(int)start, (int)end);
}
return SUCCESS;
}
/* PFADD and PFMERGE are the same except that in one case we serialize,
* and in the other case we key prefix */
static int redis_gen_pf_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, int kw_len, int is_keys, char **cmd,
int *cmd_len, short *slot)
{
smart_string cmdstr = {0};
zend_string *key = NULL;
HashTable *ht = NULL;
zval *z_ele;
int argc=1;
short s2;
// Parse arguments
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_STR(key)
Z_PARAM_ARRAY_HT(ht)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
argc += zend_hash_num_elements(ht);
// We need at least two arguments
if (argc < 2) {
return FAILURE;
}
redis_cmd_init_sstr(&cmdstr, argc, kw, kw_len);
redis_cmd_append_sstr_key_zstr(&cmdstr, key, redis_sock, slot);
// Append our array of keys or serialized values */
ZEND_HASH_FOREACH_VAL(ht, z_ele) {
if (is_keys) {
redis_cmd_append_sstr_key_zval(&cmdstr, z_ele, redis_sock, slot ? &s2 : NULL);
if (slot && *slot != s2) {
php_error_docref(0, E_WARNING, "All keys must hash to the same slot!");
return FAILURE;
}
} else {
redis_cmd_append_sstr_zval(&cmdstr, z_ele, redis_sock);
}
} ZEND_HASH_FOREACH_END();
// Push output arguments
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* PFADD */
int redis_pfadd_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
return redis_gen_pf_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock,
ZEND_STRL("PFADD"), 0, cmd, cmd_len, slot);
}
/* PFMERGE */
int redis_pfmerge_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
return redis_gen_pf_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock,
ZEND_STRL("PFMERGE"), 1, cmd, cmd_len, slot);
}
/* PFCOUNT */
int redis_pfcount_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
smart_string cmdstr = {0};
zval *zarg = NULL, *zv;
short slot2 = -1;
uint32_t keys;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ZVAL(zarg)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
if (Z_TYPE_P(zarg) == IS_STRING) {
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 1, "PFCOUNT");
redis_cmd_append_sstr_key_zstr(&cmdstr, Z_STR_P(zarg), redis_sock, slot);
} else if (Z_TYPE_P(zarg) == IS_ARRAY) {
keys = zend_hash_num_elements(Z_ARRVAL_P(zarg));
if (keys == 0)
return FAILURE;
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, keys, "PFCOUNT");
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zarg), zv) {
redis_cmd_append_sstr_key_zval(&cmdstr, zv, redis_sock, slot);
if (slot) {
if (slot2 != -1 && slot2 != *slot)
goto cross_slot;
slot2 = *slot;
}
} ZEND_HASH_FOREACH_END();
} else {
php_error_docref(NULL, E_WARNING, "Argument must be either an array or a string");
return FAILURE;
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
cross_slot:
php_error_docref(NULL, E_WARNING, "Not all keys hash to the same slot!");
efree(cmdstr.c);
return FAILURE;
}
int redis_auth_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
zend_string *user = NULL, *pass = NULL;
zval *ztest;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z!", &ztest) == FAILURE ||
redis_extract_auth_info(ztest, &user, &pass) == FAILURE)
{
return FAILURE;
}
/* Construct either AUTH or AUTH */
if (user && pass) {
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "AUTH", "SS", user, pass);
} else {
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "AUTH", "S", pass);
}
redis_sock_set_auth(redis_sock, user, pass);
if (user) zend_string_release(user);
if (pass) zend_string_release(pass);
return SUCCESS;
}
/* SETBIT */
int redis_setbit_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
char *key;
size_t key_len;
zend_long offset;
zend_bool val;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "slb", &key, &key_len,
&offset, &val) == FAILURE)
{
return FAILURE;
}
// Validate our offset
if (offset < BITOP_MIN_OFFSET || offset > BITOP_MAX_OFFSET) {
php_error_docref(0, E_WARNING,
"Invalid OFFSET for bitop command (must be between 0-2^32-1)");
return FAILURE;
}
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "SETBIT", "kld", key, key_len, offset, (int)val);
return SUCCESS;
}
int redis_lmove_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx)
{
zend_string *src = NULL, *dst = NULL, *from = NULL, *to = NULL;
smart_string cmdstr = {0};
double timeout = 0.0;
short slot2 = 0;
int blocking;
blocking = toupper(*kw) == 'B';
ZEND_PARSE_PARAMETERS_START(4 + !!blocking, 4 + !!blocking)
Z_PARAM_STR(src)
Z_PARAM_STR(dst)
Z_PARAM_STR(from)
Z_PARAM_STR(to)
if (blocking) {
Z_PARAM_DOUBLE(timeout)
}
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
if (!zend_string_equals_literal_ci(from, "LEFT") && !zend_string_equals_literal_ci(from, "RIGHT")) {
php_error_docref(NULL, E_WARNING, "Wherefrom argument must be 'LEFT' or 'RIGHT'");
return FAILURE;
} else if (!zend_string_equals_literal_ci(to, "LEFT") && !zend_string_equals_literal_ci(to, "RIGHT")) {
php_error_docref(NULL, E_WARNING, "Whereto argument must be 'LEFT' or 'RIGHT'");
return FAILURE;
}
redis_cmd_init_sstr(&cmdstr, 4 + !!blocking, kw, strlen(kw));
redis_cmd_append_sstr_key_zstr(&cmdstr, src, redis_sock, slot);
redis_cmd_append_sstr_key_zstr(&cmdstr, dst, redis_sock, slot ? &slot2 : NULL);
/* Protect the user from CROSSLOT errors */
if (slot && slot2 != *slot) {
php_error_docref(NULL, E_WARNING, "Both keys must hash to the same slot!");
efree(cmdstr.c);
return FAILURE;
}
redis_cmd_append_sstr_zstr(&cmdstr, from);
redis_cmd_append_sstr_zstr(&cmdstr, to);
if (blocking) redis_cmd_append_sstr_dbl(&cmdstr, timeout);
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* LINSERT */
int redis_linsert_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
char *key, *pos;
size_t key_len, pos_len;
zval *z_val, *z_pivot;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sszz", &key, &key_len,
&pos, &pos_len, &z_pivot, &z_val) == FAILURE)
{
return FAILURE;
}
// Validate position
if (strcasecmp(pos, "after") && strcasecmp(pos, "before")) {
php_error_docref(NULL, E_WARNING,
"Position must be either 'BEFORE' or 'AFTER'");
return FAILURE;
}
/* Construct command */
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "LINSERT", "ksvv", key, key_len, pos,
pos_len, z_pivot, z_val);
// Success
return SUCCESS;
}
/* LREM */
int redis_lrem_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
char *key;
size_t key_len;
zend_long count = 0;
zval *z_val;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz|l", &key, &key_len,
&z_val, &count) == FAILURE)
{
return FAILURE;
}
/* Construct command */
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "LREM", "kdv", key, key_len, count, z_val);
// Success!
return SUCCESS;
}
int
redis_lpos_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
char *key;
int argc = 2;
size_t key_len;
smart_string cmdstr = {0};
zend_bool withrank = 0;
zend_long rank = 0, count = -1, maxlen = -1;
zend_string *zkey;
zval *z_val, *z_ele, *z_opts = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz|a",
&key, &key_len, &z_val, &z_opts) == FAILURE)
{
return FAILURE;
}
if (z_opts != NULL) {
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(z_opts), zkey, z_ele) {
if (zkey != NULL) {
ZVAL_DEREF(z_ele);
if (zend_string_equals_literal_ci(zkey, "count")) {
count = zval_get_long(z_ele);
} else if (zend_string_equals_literal_ci(zkey, "maxlen")) {
maxlen = zval_get_long(z_ele);
} else if (zend_string_equals_literal_ci(zkey, "rank")) {
rank = zval_get_long(z_ele);
withrank = 1;
}
}
} ZEND_HASH_FOREACH_END();
}
argc += (withrank ? 2 : 0) + (count >= 0 ? 2 : 0) + (maxlen >= 0 ? 2 : 0);
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc, "LPOS");
redis_cmd_append_sstr_key(&cmdstr, key, key_len, redis_sock, slot);
redis_cmd_append_sstr_zval(&cmdstr, z_val, redis_sock);
if (withrank) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "RANK");
redis_cmd_append_sstr_long(&cmdstr, rank);
}
if (count >= 0) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "COUNT");
redis_cmd_append_sstr_long(&cmdstr, count);
*ctx = PHPREDIS_CTX_PTR;
}
if (maxlen >= 0) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "MAXLEN");
redis_cmd_append_sstr_long(&cmdstr, maxlen);
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
int redis_smove_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
zend_string *src = NULL, *dst = NULL;
smart_string cmdstr = {0};
zval *zv = NULL;
short slot2;
ZEND_PARSE_PARAMETERS_START(3, 3) {
Z_PARAM_STR(src)
Z_PARAM_STR(dst)
Z_PARAM_ZVAL(zv)
} ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 3, "SMOVE");
redis_cmd_append_sstr_key_zstr(&cmdstr, src, redis_sock, slot);
redis_cmd_append_sstr_key_zstr(&cmdstr, dst, redis_sock, slot ? &slot2 : NULL);
redis_cmd_append_sstr_zval(&cmdstr, zv, redis_sock);
if (slot && *slot != slot2) {
php_error_docref(0, E_WARNING, "Source and destination keys don't hash to the same slot!");
efree(cmdstr.c);
return FAILURE;
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* HSET */
int redis_hset_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
int i, argc;
smart_string cmdstr = {0};
zend_string *zkey;
zval *z_args, *z_ele;
if ((argc = ZEND_NUM_ARGS()) < 2) {
return FAILURE;
}
z_args = ecalloc(argc, sizeof(*z_args));
if (zend_get_parameters_array(ht, argc, z_args) == FAILURE) {
efree(z_args);
return FAILURE;
}
if (argc == 2) {
if (Z_TYPE(z_args[1]) != IS_ARRAY || zend_hash_num_elements(Z_ARRVAL(z_args[1])) == 0) {
efree(z_args);
return FAILURE;
}
/* Initialize our command */
redis_cmd_init_sstr(&cmdstr, 1 + zend_hash_num_elements(Z_ARRVAL(z_args[1])), ZEND_STRL("HSET"));
/* Append key */
zkey = zval_get_string(&z_args[0]);
redis_cmd_append_sstr_key(&cmdstr, ZSTR_VAL(zkey), ZSTR_LEN(zkey), redis_sock, slot);
zend_string_release(zkey);
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL(z_args[1]), zkey, z_ele) {
if (zkey != NULL) {
ZVAL_DEREF(z_ele);
redis_cmd_append_sstr(&cmdstr, ZSTR_VAL(zkey), ZSTR_LEN(zkey));
redis_cmd_append_sstr_zval(&cmdstr, z_ele, redis_sock);
}
} ZEND_HASH_FOREACH_END();
} else {
if (argc % 2 == 0) {
efree(z_args);
return FAILURE;
}
/* Initialize our command */
redis_cmd_init_sstr(&cmdstr, argc, ZEND_STRL("HSET"));
/* Append key */
zkey = zval_get_string(&z_args[0]);
redis_cmd_append_sstr_key(&cmdstr, ZSTR_VAL(zkey), ZSTR_LEN(zkey), redis_sock, slot);
zend_string_release(zkey);
for (i = 1; i < argc; ++i) {
if (i % 2) {
zkey = zval_get_string(&z_args[i]);
redis_cmd_append_sstr(&cmdstr, ZSTR_VAL(zkey), ZSTR_LEN(zkey));
zend_string_release(zkey);
} else {
redis_cmd_append_sstr_zval(&cmdstr, &z_args[i], redis_sock);
}
}
}
// Push out values
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
// Cleanup arg array
efree(z_args);
return SUCCESS;
}
/* HSETNX */
int redis_hsetnx_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
char *key, *mem;
size_t key_len, mem_len;
zval *z_val;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssz", &key, &key_len,
&mem, &mem_len, &z_val) == FAILURE)
{
return FAILURE;
}
/* Construct command */
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "HSETNX", "ksv", key, key_len, mem, mem_len, z_val);
// Success
return SUCCESS;
}
int
redis_hrandfield_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
char *key;
int count = 0;
size_t key_len;
smart_string cmdstr = {0};
zend_bool withvalues = 0;
zval *z_opts = NULL, *z_ele;
zend_string *zkey;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|a",
&key, &key_len, &z_opts) == FAILURE)
{
return FAILURE;
}
if (z_opts != NULL) {
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(z_opts), zkey, z_ele) {
if (zkey != NULL) {
ZVAL_DEREF(z_ele);
if (zend_string_equals_literal_ci(zkey, "count")) {
count = zval_get_long(z_ele);
} else if (zend_string_equals_literal_ci(zkey, "withvalues")) {
withvalues = zval_is_true(z_ele);
}
}
} ZEND_HASH_FOREACH_END();
}
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 1 + (count != 0) + withvalues, "HRANDFIELD");
redis_cmd_append_sstr_key(&cmdstr, key, key_len, redis_sock, slot);
if (count != 0) {
redis_cmd_append_sstr_long(&cmdstr, count);
*ctx = PHPREDIS_CTX_PTR;
}
if (withvalues) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "WITHVALUES");
*ctx = PHPREDIS_CTX_PTR + 1;
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
int redis_select_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
zend_long db = 0;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_LONG(db)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
if (db < 0 || db > INT_MAX)
return FAILURE;
*ctx = (void*)(uintptr_t)db;
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "SELECT", "d", db);
return SUCCESS;
}
/* SRANDMEMBER */
int redis_srandmember_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
uint32_t argc = ZEND_NUM_ARGS();
smart_string cmdstr = {0};
zend_string *key = NULL;
zend_long count = 0;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_STR(key)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(count)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, ZEND_NUM_ARGS(), "SRANDMEMBER");
redis_cmd_append_sstr_key_zstr(&cmdstr, key, redis_sock, slot);
if (argc == 2)
redis_cmd_append_sstr_long(&cmdstr, count);
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
*ctx = argc == 2 ? PHPREDIS_CTX_PTR : NULL;
return SUCCESS;
}
/* ZINCRBY */
int redis_zincrby_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
char *key;
size_t key_len;
double incrby;
zval *z_val;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sdz", &key, &key_len,
&incrby, &z_val) == FAILURE)
{
return FAILURE;
}
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "ZINCRBY", "kfv", key, key_len, incrby, z_val);
return SUCCESS;
}
/* SORT */
int redis_sort_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx)
{
zval *z_opts=NULL, *z_ele, z_argv;
char *key;
HashTable *ht_opts;
smart_string cmdstr = {0};
size_t key_len;
int key_free;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|a", &key, &key_len,
&z_opts) == FAILURE)
{
return FAILURE;
}
// If we don't have an options array, the command is quite simple
if (!z_opts || zend_hash_num_elements(Z_ARRVAL_P(z_opts)) == 0) {
// Construct command
*cmd_len = REDIS_CMD_SPPRINTF(cmd, kw, "k", key, key_len);
return SUCCESS;
}
// Create our hash table to hold our sort arguments
array_init(&z_argv);
// SORT
key_free = redis_key_prefix(redis_sock, &key, &key_len);
add_next_index_stringl(&z_argv, key, key_len);
if (key_free) efree(key);
// Set slot
CMD_SET_SLOT(slot,key,key_len);
// Grab the hash table
ht_opts = Z_ARRVAL_P(z_opts);
// Handle BY pattern
if (((z_ele = zend_hash_str_find(ht_opts, "by", sizeof("by") - 1)) != NULL ||
(z_ele = zend_hash_str_find(ht_opts, "BY", sizeof("BY") - 1)) != NULL
) && Z_TYPE_P(z_ele) == IS_STRING
) {
// "BY" option is disabled in cluster
if (slot) {
php_error_docref(NULL, E_WARNING,
"SORT BY option is not allowed in Redis Cluster");
zval_dtor(&z_argv);
return FAILURE;
}
// ... BY
add_next_index_stringl(&z_argv, "BY", sizeof("BY") - 1);
add_next_index_stringl(&z_argv, Z_STRVAL_P(z_ele), Z_STRLEN_P(z_ele));
}
// Handle ASC/DESC option
if (((z_ele = zend_hash_str_find(ht_opts, "sort", sizeof("sort") - 1)) != NULL ||
(z_ele = zend_hash_str_find(ht_opts, "SORT", sizeof("SORT") - 1)) != NULL
) && Z_TYPE_P(z_ele) == IS_STRING
) {
// 'asc'|'desc'
add_next_index_stringl(&z_argv, Z_STRVAL_P(z_ele), Z_STRLEN_P(z_ele));
}
// STORE option
if (((z_ele = zend_hash_str_find(ht_opts, "store", sizeof("store") - 1)) != NULL ||
(z_ele = zend_hash_str_find(ht_opts, "STORE", sizeof("STORE") - 1)) != NULL
) && Z_TYPE_P(z_ele) == IS_STRING
) {
// Slot verification
int cross_slot = slot && *slot != cluster_hash_key(
Z_STRVAL_P(z_ele), Z_STRLEN_P(z_ele));
if (cross_slot) {
php_error_docref(0, E_WARNING,
"Error, SORT key and STORE key have different slots!");
zval_dtor(&z_argv);
return FAILURE;
}
// STORE
add_next_index_stringl(&z_argv, "STORE", sizeof("STORE") - 1);
add_next_index_stringl(&z_argv, Z_STRVAL_P(z_ele), Z_STRLEN_P(z_ele));
// We are using STORE
*ctx = PHPREDIS_CTX_PTR;
}
// GET option
if (((z_ele = zend_hash_str_find(ht_opts, "get", sizeof("get") - 1)) != NULL ||
(z_ele = zend_hash_str_find(ht_opts, "GET", sizeof("GET") - 1)) != NULL
) && (Z_TYPE_P(z_ele) == IS_STRING || Z_TYPE_P(z_ele) == IS_ARRAY)
) {
// Disabled in cluster
if (slot) {
php_error_docref(NULL, E_WARNING,
"GET option for SORT disabled in Redis Cluster");
zval_dtor(&z_argv);
return FAILURE;
}
// If it's a string just add it
if (Z_TYPE_P(z_ele) == IS_STRING) {
add_next_index_stringl(&z_argv, "GET", sizeof("GET") - 1);
add_next_index_stringl(&z_argv, Z_STRVAL_P(z_ele), Z_STRLEN_P(z_ele));
} else {
int added = 0;
zval *z_key;
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(z_ele), z_key) {
// If we can't get the data, or it's not a string, skip
if (z_key == NULL || Z_TYPE_P(z_key) != IS_STRING) {
continue;
}
/* Add get per thing we're getting */
add_next_index_stringl(&z_argv, "GET", sizeof("GET") - 1);
// Add this key to our argv array
add_next_index_stringl(&z_argv, Z_STRVAL_P(z_key), Z_STRLEN_P(z_key));
added++;
} ZEND_HASH_FOREACH_END();
// Make sure we were able to add at least one
if (added == 0) {
php_error_docref(NULL, E_WARNING,
"Array of GET values requested, but none are valid");
zval_dtor(&z_argv);
return FAILURE;
}
}
}
// ALPHA
if (((z_ele = zend_hash_str_find(ht_opts, "alpha", sizeof("alpha") - 1)) != NULL ||
(z_ele = zend_hash_str_find(ht_opts, "ALPHA", sizeof("ALPHA") - 1)) != NULL) &&
zval_is_true(z_ele)
) {
add_next_index_stringl(&z_argv, "ALPHA", sizeof("ALPHA") - 1);
}
// LIMIT
if (((z_ele = zend_hash_str_find(ht_opts, "limit", sizeof("limit") - 1)) != NULL ||
(z_ele = zend_hash_str_find(ht_opts, "LIMIT", sizeof("LIMIT") - 1)) != NULL
) && Z_TYPE_P(z_ele) == IS_ARRAY
) {
HashTable *ht_off = Z_ARRVAL_P(z_ele);
zval *z_off, *z_cnt;
if ((z_off = zend_hash_index_find(ht_off, 0)) != NULL &&
(z_cnt = zend_hash_index_find(ht_off, 1)) != NULL
) {
if ((Z_TYPE_P(z_off) != IS_STRING && Z_TYPE_P(z_off) != IS_LONG) ||
(Z_TYPE_P(z_cnt) != IS_STRING && Z_TYPE_P(z_cnt) != IS_LONG)
) {
php_error_docref(NULL, E_WARNING,
"LIMIT options on SORT command must be longs or strings");
zval_dtor(&z_argv);
return FAILURE;
}
// Add LIMIT argument
add_next_index_stringl(&z_argv, "LIMIT", sizeof("LIMIT") - 1);
long low, high;
if (Z_TYPE_P(z_off) == IS_STRING) {
low = atol(Z_STRVAL_P(z_off));
} else {
low = Z_LVAL_P(z_off);
}
if (Z_TYPE_P(z_cnt) == IS_STRING) {
high = atol(Z_STRVAL_P(z_cnt));
} else {
high = Z_LVAL_P(z_cnt);
}
// Add our two LIMIT arguments
add_next_index_long(&z_argv, low);
add_next_index_long(&z_argv, high);
}
}
// Start constructing our command
HashTable *ht_argv = Z_ARRVAL_P(&z_argv);
redis_cmd_init_sstr(&cmdstr, zend_hash_num_elements(ht_argv), kw, strlen(kw));
// Iterate through our arguments
ZEND_HASH_FOREACH_VAL(ht_argv, z_ele) {
// Args are strings or longs
if (Z_TYPE_P(z_ele) == IS_STRING) {
redis_cmd_append_sstr(&cmdstr,Z_STRVAL_P(z_ele),
Z_STRLEN_P(z_ele));
} else {
redis_cmd_append_sstr_long(&cmdstr, Z_LVAL_P(z_ele));
}
} ZEND_HASH_FOREACH_END();
/* Clean up our arguments array. Note we don't have to free any prefixed
* key as that we didn't duplicate the pointer if we prefixed */
zval_dtor(&z_argv);
// Push our length and command
*cmd_len = cmdstr.len;
*cmd = cmdstr.c;
// Success!
return SUCCESS;
}
/* HDEL */
int redis_hdel_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
zval *z_args;
smart_string cmdstr = {0};
char *arg;
int arg_free, i;
size_t arg_len;
int argc = ZEND_NUM_ARGS();
zend_string *zstr;
// We need at least KEY and one member
if (argc < 2) {
return FAILURE;
}
// Grab arguments as an array
z_args = emalloc(argc * sizeof(zval));
if (zend_get_parameters_array(ht, argc, z_args) == FAILURE) {
efree(z_args);
return FAILURE;
}
// Get first argument (the key) as a string
zstr = zval_get_string(&z_args[0]);
arg = ZSTR_VAL(zstr);
arg_len = ZSTR_LEN(zstr);
// Prefix
arg_free = redis_key_prefix(redis_sock, &arg, &arg_len);
// Start command construction
redis_cmd_init_sstr(&cmdstr, argc, ZEND_STRL("HDEL"));
redis_cmd_append_sstr(&cmdstr, arg, arg_len);
// Set our slot, free key if we prefixed it
CMD_SET_SLOT(slot,arg,arg_len);
zend_string_release(zstr);
if (arg_free) efree(arg);
// Iterate through the members we're removing
for (i = 1; i < argc; i++) {
zstr = zval_get_string(&z_args[i]);
redis_cmd_append_sstr(&cmdstr, ZSTR_VAL(zstr), ZSTR_LEN(zstr));
zend_string_release(zstr);
}
// Push out values
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
// Cleanup
efree(z_args);
// Success!
return SUCCESS;
}
/* ZADD */
int redis_zadd_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
zend_string *zstr, *key = NULL, *exp_type = NULL, *range_type = NULL;
zend_bool ch = 0, incr = 0;
smart_string cmdstr = {0};
zval *argv = NULL, *z_opt;
int argc = 0, pos = 0;
ZEND_PARSE_PARAMETERS_START(3, -1)
Z_PARAM_STR(key)
Z_PARAM_VARIADIC('*', argv, argc)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
// Need key, [NX|XX] [LT|GT] [CH] [INCR] score, value, [score, value...] */
if (argc % 2 != 0) {
if (Z_TYPE(argv[0]) != IS_ARRAY) {
return FAILURE;
}
ZEND_HASH_FOREACH_VAL(Z_ARRVAL(argv[0]), z_opt) {
if (Z_TYPE_P(z_opt) == IS_STRING) {
zstr = Z_STR_P(z_opt);
if (zend_string_equals_literal_ci(zstr, "NX") || zend_string_equals_literal_ci(zstr, "XX")) {
exp_type = Z_STR_P(z_opt);
} else if (zend_string_equals_literal_ci(zstr, "LT") || zend_string_equals_literal_ci(zstr, "GT")) {
range_type = Z_STR_P(z_opt);
} else if (zend_string_equals_literal_ci(zstr, "CH")) {
ch = 1;
} else if (zend_string_equals_literal_ci(zstr, "INCR")) {
if (argc != 3) {
// Only one score-element pair can be specified in this mode.
return FAILURE;
}
incr = 1;
}
}
} ZEND_HASH_FOREACH_END();
pos++;
}
// Start command construction
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 1 + (argc - pos) + !!exp_type + !!range_type + !!ch + !!incr, "ZADD");
redis_cmd_append_sstr_key_zstr(&cmdstr, key, redis_sock, slot);
if (exp_type) redis_cmd_append_sstr_zstr(&cmdstr, exp_type);
if (range_type) redis_cmd_append_sstr_zstr(&cmdstr, range_type);
REDIS_CMD_APPEND_SSTR_OPT_STATIC(&cmdstr, ch, "CH");
REDIS_CMD_APPEND_SSTR_OPT_STATIC(&cmdstr, incr, "INCR");
// Now the rest of our arguments
while (pos < argc) {
// Append score and member
if (redis_cmd_append_sstr_score(&cmdstr, &argv[pos]) == FAILURE) {
smart_string_free(&cmdstr);
return FAILURE;
}
redis_cmd_append_sstr_zval(&cmdstr, &argv[pos+1], redis_sock);
pos += 2;
}
// Push output values
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
*ctx = incr ? PHPREDIS_CTX_PTR : NULL;
return SUCCESS;
}
/* OBJECT */
int redis_object_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
zend_string *subcmd = NULL, *key = NULL;
smart_string cmdstr = {0};
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_STR(subcmd)
Z_PARAM_STR(key)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
if (zend_string_equals_literal_ci(subcmd, "REFCOUNT") ||
zend_string_equals_literal_ci(subcmd, "IDLETIME"))
{
*ctx = PHPREDIS_CTX_PTR;
} else if (zend_string_equals_literal_ci(subcmd, "ENCODING")) {
*ctx = PHPREDIS_CTX_PTR + 1;
} else {
php_error_docref(NULL, E_WARNING, "Invalid subcommand sent to OBJECT");
return FAILURE;
}
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 2, "OBJECT");
redis_cmd_append_sstr_zstr(&cmdstr, subcmd);
redis_cmd_append_sstr_key_zstr(&cmdstr, key, redis_sock, slot);
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
int
redis_geoadd_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
zval *z_args, *z_ele;
smart_string cmdstr = {0};
zend_bool ch = 0;
zend_string *zstr;
char *mode = NULL;
int argc, i;
// We at least need a key and three values
if ((argc = ZEND_NUM_ARGS()) < 4 || (argc % 3 != 1 && argc % 3 != 2)) {
zend_wrong_param_count();
return FAILURE;
}
// Make sure we at least have a key, and we can get other args
z_args = ecalloc(argc, sizeof(*z_args));
if (zend_get_parameters_array(ht, argc, z_args) == FAILURE) {
efree(z_args);
return FAILURE;
}
if (argc % 3 == 2) {
argc--;
if (Z_TYPE(z_args[argc]) != IS_ARRAY) {
php_error_docref(NULL, E_WARNING, "Invalid options value");
efree(z_args);
return FAILURE;
}
ZEND_HASH_FOREACH_VAL(Z_ARRVAL(z_args[argc]), z_ele) {
ZVAL_DEREF(z_ele);
if (Z_TYPE_P(z_ele) == IS_STRING) {
if (zend_string_equals_literal_ci(Z_STR_P(z_ele), "NX") ||
zend_string_equals_literal_ci(Z_STR_P(z_ele), "XX"))
{
mode = Z_STRVAL_P(z_ele);
} else if (zend_string_equals_literal_ci(Z_STR_P(z_ele), "CH")) {
ch = 1;
}
}
} ZEND_HASH_FOREACH_END();
}
/* Initialize our command */
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc + (mode != NULL) + ch, "GEOADD");
/* Append key */
zstr = zval_get_string(&z_args[0]);
redis_cmd_append_sstr_key(&cmdstr, ZSTR_VAL(zstr), ZSTR_LEN(zstr), redis_sock, slot);
zend_string_release(zstr);
/* Append options */
if (mode != NULL) {
redis_cmd_append_sstr(&cmdstr, mode, strlen(mode));
}
REDIS_CMD_APPEND_SSTR_OPT_STATIC(&cmdstr, ch, "CH");
/* Append members */
for (i = 1; i < argc; ++i) {
redis_cmd_append_sstr_zval(&cmdstr, &z_args[i], redis_sock);
}
// Cleanup arg array
efree(z_args);
// Push out values
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* GEODIST */
int redis_geodist_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
char *key, *source, *dest, *unit = NULL;
size_t keylen, sourcelen, destlen, unitlen;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|s", &key, &keylen,
&source, &sourcelen, &dest, &destlen, &unit,
&unitlen) == FAILURE)
{
return FAILURE;
}
/* Construct command */
if (unit != NULL) {
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "GEODIST", "ksss", key, keylen, source,
sourcelen, dest, destlen, unit, unitlen);
} else {
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "GEODIST", "kss", key, keylen, source,
sourcelen, dest, destlen);
}
return SUCCESS;
}
geoStoreType get_georadius_store_type(zend_string *key) {
if (ZSTR_LEN(key) == 5 && !strcasecmp(ZSTR_VAL(key), "store")) {
return STORE_COORD;
} else if (ZSTR_LEN(key) == 9 && !strcasecmp(ZSTR_VAL(key), "storedist")) {
return STORE_DIST;
}
return STORE_NONE;
}
/* Helper function to get COUNT and possible ANY flag which is passable to
* both GEORADIUS and GEOSEARCH */
static int get_georadius_count_options(zval *optval, geoOptions *opts) {
zval *z_tmp;
/* Short circuit on bad options */
if (Z_TYPE_P(optval) != IS_ARRAY && Z_TYPE_P(optval) != IS_LONG)
goto error;
if (Z_TYPE_P(optval) == IS_ARRAY) {
z_tmp = zend_hash_index_find(Z_ARRVAL_P(optval), 0);
if (z_tmp) {
if (Z_TYPE_P(z_tmp) != IS_LONG || Z_LVAL_P(z_tmp) <= 0)
goto error;
opts->count = Z_LVAL_P(z_tmp);
}
z_tmp = zend_hash_index_find(Z_ARRVAL_P(optval), 1);
if (z_tmp) {
opts->any = zval_is_true(z_tmp);
}
} else {
if (Z_LVAL_P(optval) <= 0)
goto error;
opts->count = Z_LVAL_P(optval);
}
return SUCCESS;
error:
php_error_docref(NULL, E_WARNING, "Invalid COUNT value");
return FAILURE;
}
/* Helper function to extract optional arguments for GEORADIUS and GEORADIUSBYMEMBER */
static int get_georadius_opts(HashTable *ht, geoOptions *opts) {
zend_string *zkey;
char *optstr;
zval *optval;
/* Iterate over our argument array, collating which ones we have */
ZEND_HASH_FOREACH_STR_KEY_VAL(ht, zkey, optval) {
ZVAL_DEREF(optval);
/* If the key is numeric it's a non value option */
if (zkey) {
if (zend_string_equals_literal_ci(zkey, "COUNT")) {
if (get_georadius_count_options(optval, opts) == FAILURE) {
if (opts->key) zend_string_release(opts->key);
return FAILURE;
}
} else if (opts->store == STORE_NONE) {
opts->store = get_georadius_store_type(zkey);
if (opts->store != STORE_NONE) {
opts->key = zval_get_string(optval);
}
}
} else {
/* Option needs to be a string */
if (Z_TYPE_P(optval) != IS_STRING) continue;
optstr = Z_STRVAL_P(optval);
if (!strcasecmp(optstr, "withcoord")) {
opts->withcoord = 1;
} else if (!strcasecmp(optstr, "withdist")) {
opts->withdist = 1;
} else if (!strcasecmp(optstr, "withhash")) {
opts->withhash = 1;
} else if (!strcasecmp(optstr, "asc")) {
opts->sort = SORT_ASC;
} else if (!strcasecmp(optstr, "desc")) {
opts->sort = SORT_DESC;
}
}
} ZEND_HASH_FOREACH_END();
/* STORE and STOREDIST are not compatible with the WITH* options */
if (opts->key != NULL && (opts->withcoord || opts->withdist || opts->withhash)) {
php_error_docref(NULL, E_WARNING,
"STORE[DIST] is not compatible with WITHCOORD, WITHDIST or WITHHASH");
if (opts->key) zend_string_release(opts->key);
return FAILURE;
}
/* Success */
return SUCCESS;
}
/* Helper to append options to a GEORADIUS or GEORADIUSBYMEMBER command */
void append_georadius_opts(RedisSock *redis_sock, smart_string *str, short *slot,
geoOptions *opt)
{
if (opt->withcoord)
REDIS_CMD_APPEND_SSTR_STATIC(str, "WITHCOORD");
if (opt->withdist)
REDIS_CMD_APPEND_SSTR_STATIC(str, "WITHDIST");
if (opt->withhash)
REDIS_CMD_APPEND_SSTR_STATIC(str, "WITHHASH");
/* Append sort if it's not GEO_NONE */
if (opt->sort == SORT_ASC) {
REDIS_CMD_APPEND_SSTR_STATIC(str, "ASC");
} else if (opt->sort == SORT_DESC) {
REDIS_CMD_APPEND_SSTR_STATIC(str, "DESC");
}
/* Append our count if we've got one */
if (opt->count) {
REDIS_CMD_APPEND_SSTR_STATIC(str, "COUNT");
redis_cmd_append_sstr_long(str, opt->count);
if (opt->any) {
REDIS_CMD_APPEND_SSTR_STATIC(str, "ANY");
}
}
/* Append store options if we've got them */
if (opt->store != STORE_NONE && opt->key != NULL) {
if (opt->store == STORE_COORD) {
REDIS_CMD_APPEND_SSTR_STATIC(str, "STORE");
} else {
REDIS_CMD_APPEND_SSTR_STATIC(str, "STOREDIST");
}
redis_cmd_append_sstr_key_zstr(str, opt->key, redis_sock, slot);
}
}
/* GEORADIUS / GEORADIUS_RO */
int redis_georadius_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
zend_string *key = NULL, *unit = NULL;
double lng = 0, lat = 0, radius = 0;
smart_string cmdstr = {0};
HashTable *opts = NULL;
geoOptions gopts = {0};
short store_slot = -1;
uint32_t argc;
ZEND_PARSE_PARAMETERS_START(5, 6)
Z_PARAM_STR(key)
Z_PARAM_DOUBLE(lng)
Z_PARAM_DOUBLE(lat)
Z_PARAM_DOUBLE(radius)
Z_PARAM_STR(unit)
Z_PARAM_OPTIONAL
Z_PARAM_ARRAY_HT_OR_NULL(opts)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
/* Parse any GEORADIUS options we have */
if (opts != NULL && get_georadius_opts(opts, &gopts) != SUCCESS)
return FAILURE;
/* Increment argc depending on options */
argc = 5 + gopts.withcoord + gopts.withdist + gopts.withhash +
(gopts.sort != SORT_NONE) + (gopts.count ? 2 + gopts.any : 0) +
(gopts.store != STORE_NONE ? 2 : 0);
/* Begin construction of our command */
redis_cmd_init_sstr(&cmdstr, argc, kw, strlen(kw));
redis_cmd_append_sstr_key_zstr(&cmdstr, key, redis_sock, slot);
/* Append required arguments */
redis_cmd_append_sstr_dbl(&cmdstr, lng);
redis_cmd_append_sstr_dbl(&cmdstr, lat);
redis_cmd_append_sstr_dbl(&cmdstr, radius);
redis_cmd_append_sstr_zstr(&cmdstr, unit);
/* Append optional arguments */
append_georadius_opts(redis_sock, &cmdstr, slot ? &store_slot : NULL, &gopts);
/* Free key if it was prefixed */
if (gopts.key) zend_string_release(gopts.key);
/* Protect the user from CROSSSLOT if we're in cluster */
if (slot && gopts.store != STORE_NONE && *slot != store_slot) {
php_error_docref(NULL, E_WARNING,
"Key and STORE[DIST] key must hash to the same slot");
efree(cmdstr.c);
return FAILURE;
}
/* Set slot, command and len, and return */
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* GEORADIUSBYMEMBER/GEORADIUSBYMEMBER_RO
* key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] */
int redis_georadiusbymember_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
char *key, *mem, *unit;
size_t keylen, memlen, unitlen;
short store_slot = 0;
int keyfree, argc = 4;
double radius;
geoOptions gopts = {0};
zval *opts = NULL;
smart_string cmdstr = {0};
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssds|a", &key, &keylen,
&mem, &memlen, &radius, &unit, &unitlen, &opts) == FAILURE)
{
return FAILURE;
}
if (opts != NULL) {
/* Attempt to parse our options array */
if (get_georadius_opts(Z_ARRVAL_P(opts), &gopts) == FAILURE) {
return FAILURE;
}
}
/* Increment argc based on options */
argc += gopts.withcoord + gopts.withdist + gopts.withhash +
(gopts.sort != SORT_NONE) + (gopts.count ? 2 + gopts.any : 0) +
(gopts.store != STORE_NONE ? 2 : 0);
/* Begin command construction*/
redis_cmd_init_sstr(&cmdstr, argc, kw, strlen(kw));
/* Prefix our key if we're prefixing and set the slot */
keyfree = redis_key_prefix(redis_sock, &key, &keylen);
CMD_SET_SLOT(slot, key, keylen);
/* Append required arguments */
redis_cmd_append_sstr(&cmdstr, key, keylen);
redis_cmd_append_sstr(&cmdstr, mem, memlen);
redis_cmd_append_sstr_long(&cmdstr, radius);
redis_cmd_append_sstr(&cmdstr, unit, unitlen);
/* Append options */
append_georadius_opts(redis_sock, &cmdstr, slot ? &store_slot : NULL, &gopts);
/* Free key if we prefixed */
if (keyfree) efree(key);
if (gopts.key) zend_string_release(gopts.key);
/* Protect the user from CROSSSLOT if we're in cluster */
if (slot && gopts.store != STORE_NONE && *slot != store_slot) {
php_error_docref(NULL, E_WARNING,
"Key and STORE[DIST] key must hash to the same slot");
efree(cmdstr.c);
return FAILURE;
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
int
redis_geosearch_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
char *key, *unit;
int argc = 2;
size_t keylen, unitlen;
geoOptions gopts = {0};
smart_string cmdstr = {0};
zval *position, *shape, *opts = NULL, *z_ele;
zend_string *zkey, *zstr;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "szzs|a",
&key, &keylen, &position, &shape,
&unit, &unitlen, &opts) == FAILURE)
{
return FAILURE;
}
if (Z_TYPE_P(position) == IS_STRING && Z_STRLEN_P(position) > 0) {
argc += 2;
} else if (Z_TYPE_P(position) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(position)) == 2) {
argc += 3;
} else {
php_error_docref(NULL, E_WARNING, "Invalid position");
return FAILURE;
}
if (Z_TYPE_P(shape) == IS_LONG || Z_TYPE_P(shape) == IS_DOUBLE) {
argc += 2;
} else if (Z_TYPE_P(shape) == IS_ARRAY) {
argc += 3;
} else {
php_error_docref(NULL, E_WARNING, "Invalid shape dimensions");
return FAILURE;
}
/* Attempt to parse our options array */
if (opts != NULL) {
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(opts), zkey, z_ele) {
ZVAL_DEREF(z_ele);
if (zkey != NULL && zend_string_equals_literal_ci(zkey, "COUNT")) {
if (get_georadius_count_options(z_ele, &gopts) == FAILURE) {
return FAILURE;
}
} else if (Z_TYPE_P(z_ele) == IS_STRING) {
zstr = Z_STR_P(z_ele);
if (zend_string_equals_literal_ci(zstr, "WITHCOORD")) {
gopts.withcoord = 1;
} else if (zend_string_equals_literal_ci(zstr, "WITHDIST")) {
gopts.withdist = 1;
} else if (zend_string_equals_literal_ci(zstr, "WITHHASH")) {
gopts.withhash = 1;
} else if (zend_string_equals_literal_ci(zstr, "ASC")) {
gopts.sort = SORT_ASC;
} else if (zend_string_equals_literal_ci(zstr, "DESC")) {
gopts.sort = SORT_DESC;
}
}
} ZEND_HASH_FOREACH_END();
}
/* Increment argc based on options */
argc += gopts.withcoord + gopts.withdist + gopts.withhash
+ (gopts.sort != SORT_NONE) + (gopts.count ? 2 + gopts.any : 0);
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc, "GEOSEARCH");
redis_cmd_append_sstr_key(&cmdstr, key, keylen, redis_sock, slot);
if (Z_TYPE_P(position) == IS_ARRAY) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "FROMLONLAT");
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(position), z_ele) {
ZVAL_DEREF(z_ele);
redis_cmd_append_sstr_dbl(&cmdstr, zval_get_double(z_ele));
} ZEND_HASH_FOREACH_END();
} else {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "FROMMEMBER");
redis_cmd_append_sstr(&cmdstr, Z_STRVAL_P(position), Z_STRLEN_P(position));
}
if (Z_TYPE_P(shape) == IS_ARRAY) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "BYBOX");
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(shape), z_ele) {
ZVAL_DEREF(z_ele);
redis_cmd_append_sstr_dbl(&cmdstr, zval_get_double(z_ele));
} ZEND_HASH_FOREACH_END();
} else {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "BYRADIUS");
redis_cmd_append_sstr_dbl(&cmdstr, zval_get_double(shape));
}
redis_cmd_append_sstr(&cmdstr, unit, unitlen);
/* Append optional arguments */
if (gopts.withcoord) REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "WITHCOORD");
if (gopts.withdist) REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "WITHDIST");
if (gopts.withhash) REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "WITHHASH");
/* Append sort if it's not GEO_NONE */
if (gopts.sort == SORT_ASC) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "ASC");
} else if (gopts.sort == SORT_DESC) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "DESC");
}
/* Append our count if we've got one */
if (gopts.count) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "COUNT");
redis_cmd_append_sstr_long(&cmdstr, gopts.count);
if (gopts.any) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "ANY");
}
}
if ((argc = gopts.withcoord + gopts.withdist + gopts.withhash) > 0) {
*ctx = PHPREDIS_CTX_PTR;
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
int
redis_geosearchstore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
int argc = 3;
char *dest, *src, *unit;
size_t destlen, srclen, unitlen;
geoOptions gopts = {0};
smart_string cmdstr = {0};
zval *position, *shape, *opts = NULL, *z_ele;
zend_string *zkey;
short s2 = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sszzs|a",
&dest, &destlen, &src, &srclen, &position, &shape,
&unit, &unitlen, &opts) == FAILURE)
{
return FAILURE;
}
if (Z_TYPE_P(position) == IS_STRING && Z_STRLEN_P(position) > 0) {
argc += 2;
} else if (Z_TYPE_P(position) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(position)) == 2) {
argc += 3;
} else {
php_error_docref(NULL, E_WARNING, "Invalid position");
return FAILURE;
}
if (Z_TYPE_P(shape) == IS_LONG || Z_TYPE_P(shape) == IS_DOUBLE) {
argc += 2;
} else if (Z_TYPE_P(shape) == IS_ARRAY) {
argc += 3;
} else {
php_error_docref(NULL, E_WARNING, "Invalid shape dimensions");
return FAILURE;
}
/* Attempt to parse our options array */
if (opts != NULL) {
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(opts), zkey, z_ele) {
ZVAL_DEREF(z_ele);
if (zkey != NULL) {
if (zend_string_equals_literal_ci(zkey, "COUNT")) {
if (Z_TYPE_P(z_ele) != IS_LONG || Z_LVAL_P(z_ele) <= 0) {
php_error_docref(NULL, E_WARNING, "COUNT must be an integer > 0!");
return FAILURE;
}
gopts.count = Z_LVAL_P(z_ele);
}
} else if (Z_TYPE_P(z_ele) == IS_STRING) {
if (!strcasecmp(Z_STRVAL_P(z_ele), "ASC")) {
gopts.sort = SORT_ASC;
} else if (!strcasecmp(Z_STRVAL_P(z_ele), "DESC")) {
gopts.sort = SORT_DESC;
} else if (!strcasecmp(Z_STRVAL_P(z_ele), "STOREDIST")) {
gopts.store = STORE_DIST;
}
}
} ZEND_HASH_FOREACH_END();
}
/* Increment argc based on options */
argc += gopts.withcoord + gopts.withdist + gopts.withhash
+ (gopts.sort != SORT_NONE) + (gopts.count ? 2 : 0)
+ (gopts.store != STORE_NONE);
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc, "GEOSEARCHSTORE");
redis_cmd_append_sstr_key(&cmdstr, dest, destlen, redis_sock, slot);
redis_cmd_append_sstr_key(&cmdstr, src, srclen, redis_sock, slot ? &s2 : NULL);
if (slot && *slot != s2) {
php_error_docref(NULL, E_WARNING, "All keys must hash to the same slot");
efree(cmdstr.c);
return FAILURE;
}
if (Z_TYPE_P(position) == IS_ARRAY) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "FROMLONLAT");
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(position), z_ele) {
ZVAL_DEREF(z_ele);
redis_cmd_append_sstr_dbl(&cmdstr, zval_get_double(z_ele));
} ZEND_HASH_FOREACH_END();
} else {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "FROMMEMBER");
redis_cmd_append_sstr(&cmdstr, Z_STRVAL_P(position), Z_STRLEN_P(position));
}
if (Z_TYPE_P(shape) == IS_ARRAY) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "BYBOX");
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(shape), z_ele) {
ZVAL_DEREF(z_ele);
redis_cmd_append_sstr_dbl(&cmdstr, zval_get_double(z_ele));
} ZEND_HASH_FOREACH_END();
} else {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "BYRADIUS");
redis_cmd_append_sstr_dbl(&cmdstr, zval_get_double(shape));
}
redis_cmd_append_sstr(&cmdstr, unit, unitlen);
/* Append sort if it's not GEO_NONE */
if (gopts.sort == SORT_ASC) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "ASC");
} else if (gopts.sort == SORT_DESC) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "DESC");
}
/* Append our count if we've got one */
if (gopts.count) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "COUNT");
redis_cmd_append_sstr_long(&cmdstr, gopts.count);
}
if (gopts.store == STORE_DIST) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "STOREDIST");
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* MIGRATE host port destination-db timeout [COPY] [REPLACE]
[[AUTH password] | [AUTH2 username password]] [KEYS key [key ...]]
Starting with Redis version 3.0.0: Added the COPY and REPLACE options.
Starting with Redis version 3.0.6: Added the KEYS option.
Starting with Redis version 4.0.7: Added the AUTH option.
Starting with Redis version 6.0.0: Added the AUTH2 option.
*/
/* MIGRATE */
int redis_migrate_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
zend_string *host = NULL, *key = NULL, *user = NULL, *pass = NULL;
zend_long destdb = 0, port = 0, timeout = 0;
zval *zkeys = NULL, *zkey, *zauth = NULL;
zend_bool copy = 0, replace = 0;
smart_string cmdstr = {0};
int argc;
ZEND_PARSE_PARAMETERS_START(5, 8)
Z_PARAM_STR(host)
Z_PARAM_LONG(port)
Z_PARAM_ZVAL(zkeys)
Z_PARAM_LONG(destdb)
Z_PARAM_LONG(timeout)
Z_PARAM_OPTIONAL
Z_PARAM_BOOL(copy)
Z_PARAM_BOOL(replace)
Z_PARAM_ZVAL_OR_NULL(zauth)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
/* Sanity check on our optional AUTH argument */
if (zauth && redis_extract_auth_info(zauth, &user, &pass) == FAILURE) {
php_error_docref(NULL, E_WARNING, "AUTH must be a string or an array with one or two strings");
user = pass = NULL;
}
/* Protect against being passed an array with zero elements */
if (Z_TYPE_P(zkeys) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(zkeys)) == 0) {
php_error_docref(NULL, E_WARNING, "Keys array cannot be empty");
return FAILURE;
}
/* host, port, key|"", dest-db, timeout, [copy, replace] [KEYS key1..keyN] */
argc = 5 + copy + replace + (user||pass ? 1 : 0) + (user != NULL) + (pass != NULL);
if (Z_TYPE_P(zkeys) == IS_ARRAY) {
/* +1 for the "KEYS" argument itself */
argc += 1 + zend_hash_num_elements(Z_ARRVAL_P(zkeys));
}
/* Initialize MIGRATE command with host and port */
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc, "MIGRATE");
redis_cmd_append_sstr_zstr(&cmdstr, host);
redis_cmd_append_sstr_long(&cmdstr, port);
/* If passed a keys array the keys come later, otherwise pass the key to
* migrate here */
if (Z_TYPE_P(zkeys) == IS_ARRAY) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "");
} else {
key = redis_key_prefix_zval(redis_sock, zkeys);
redis_cmd_append_sstr_zstr(&cmdstr, key);
zend_string_release(key);
}
redis_cmd_append_sstr_long(&cmdstr, destdb);
redis_cmd_append_sstr_long(&cmdstr, timeout);
REDIS_CMD_APPEND_SSTR_OPT_STATIC(&cmdstr, copy, "COPY");
REDIS_CMD_APPEND_SSTR_OPT_STATIC(&cmdstr, replace, "REPLACE");
if (user && pass) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "AUTH2");
redis_cmd_append_sstr_zstr(&cmdstr, user);
redis_cmd_append_sstr_zstr(&cmdstr, pass);
} else if (pass) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "AUTH");
redis_cmd_append_sstr_zstr(&cmdstr, pass);
}
/* Append actual keys if we've got a keys array */
if (Z_TYPE_P(zkeys) == IS_ARRAY) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "KEYS");
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zkeys), zkey) {
key = redis_key_prefix_zval(redis_sock, zkey);
redis_cmd_append_sstr_zstr(&cmdstr, key);
zend_string_release(key);
} ZEND_HASH_FOREACH_END();
}
if (user) zend_string_release(user);
if (pass) zend_string_release(pass);
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* A generic passthru function for variadic key commands that take one or more
* keys. This is essentially all of them except ones that STORE data. */
int redis_varkey_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx)
{
return gen_varkey_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock,
kw, strlen(kw), 0, cmd, cmd_len, slot);
}
static int
redis_build_client_list_command(smart_string *cmdstr, int argc, zval *z_args)
{
zend_string *zkey;
zval *z_ele, *type = NULL, *id = NULL;
if (argc > 0) {
if (Z_TYPE(z_args[0]) != IS_ARRAY) {
return FAILURE;
}
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL(z_args[0]), zkey, z_ele) {
if (zkey != NULL) {
ZVAL_DEREF(z_ele);
if (zend_string_equals_literal_ci(zkey, "type")) {
if (Z_TYPE_P(z_ele) != IS_STRING || (
!ZVAL_STRICMP_STATIC(z_ele, "normal") &&
!ZVAL_STRICMP_STATIC(z_ele, "master") &&
!ZVAL_STRICMP_STATIC(z_ele, "replica") &&
!ZVAL_STRICMP_STATIC(z_ele, "pubsub")
)) {
return FAILURE;
}
type = z_ele;
} else if (zend_string_equals_literal_ci(zkey, "id")) {
if (Z_TYPE_P(z_ele) != IS_STRING && (
Z_TYPE_P(z_ele) != IS_ARRAY ||
!zend_hash_num_elements(Z_ARRVAL_P(z_ele))
)) {
return FAILURE;
}
id = z_ele;
}
}
} ZEND_HASH_FOREACH_END();
}
REDIS_CMD_INIT_SSTR_STATIC(cmdstr, 1 + (type ? 2 : 0) + (
id ? (Z_TYPE_P(id) == IS_ARRAY ? 1 + zend_hash_num_elements(Z_ARRVAL_P(id)) : 2) : 0
), "CLIENT");
REDIS_CMD_APPEND_SSTR_STATIC(cmdstr, "LIST");
if (type != NULL) {
REDIS_CMD_APPEND_SSTR_STATIC(cmdstr, "TYPE");
redis_cmd_append_sstr(cmdstr, Z_STRVAL_P(type), Z_STRLEN_P(type));
}
if (id != NULL) {
REDIS_CMD_APPEND_SSTR_STATIC(cmdstr, "ID");
if (Z_TYPE_P(id) == IS_ARRAY) {
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(id), z_ele) {
if (Z_TYPE_P(z_ele) == IS_STRING) {
redis_cmd_append_sstr(cmdstr, Z_STRVAL_P(z_ele), Z_STRLEN_P(z_ele));
} else {
zkey = zval_get_string(z_ele);
redis_cmd_append_sstr(cmdstr, ZSTR_VAL(zkey), ZSTR_LEN(zkey));
zend_string_release(zkey);
}
} ZEND_HASH_FOREACH_END();
} else {
redis_cmd_append_sstr(cmdstr, Z_STRVAL_P(id), Z_STRLEN_P(id));
}
}
return SUCCESS;
}
static int
redis_build_client_kill_command(smart_string *cmdstr, int argc, zval *z_args)
{
zend_string *zkey;
zval *z_ele, *id = NULL, *type = NULL, *address = NULL, *opts = NULL,
*user = NULL, *addr = NULL, *laddr = NULL, *skipme = NULL;
if (argc > 0) {
if (argc > 1) {
if (Z_TYPE(z_args[0]) != IS_STRING || Z_TYPE(z_args[1]) != IS_ARRAY) {
return FAILURE;
}
address = &z_args[0];
opts = &z_args[1];
} else if (Z_TYPE(z_args[0]) == IS_STRING) {
address = &z_args[0];
} else if (Z_TYPE(z_args[0]) == IS_ARRAY) {
opts = &z_args[0];
} else {
return FAILURE;
}
if (opts != NULL) {
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(opts), zkey, z_ele) {
if (zkey != NULL) {
ZVAL_DEREF(z_ele);
if (Z_TYPE_P(z_ele) != IS_STRING) {
return FAILURE;
}
if (zend_string_equals_literal_ci(zkey, "id")) {
id = z_ele;
} else if (zend_string_equals_literal_ci(zkey, "type")) {
if (!ZVAL_STRICMP_STATIC(z_ele, "normal") &&
!ZVAL_STRICMP_STATIC(z_ele, "master") &&
!ZVAL_STRICMP_STATIC(z_ele, "slave") &&
!ZVAL_STRICMP_STATIC(z_ele, "replica") &&
!ZVAL_STRICMP_STATIC(z_ele, "pubsub")
) {
return FAILURE;
}
type = z_ele;
} else if (zend_string_equals_literal_ci(zkey, "user")) {
user = z_ele;
} else if (zend_string_equals_literal_ci(zkey, "addr")) {
addr = z_ele;
} else if (zend_string_equals_literal_ci(zkey, "laddr")) {
laddr = z_ele;
} else if (zend_string_equals_literal_ci(zkey, "skipme")) {
if (!ZVAL_STRICMP_STATIC(z_ele, "yes") &&
!ZVAL_STRICMP_STATIC(z_ele, "no")
) {
return FAILURE;
}
skipme = z_ele;
}
}
} ZEND_HASH_FOREACH_END();
}
}
REDIS_CMD_INIT_SSTR_STATIC(cmdstr, 1 + (address != 0) + (id ? 2 : 0)
+ (type ? 2 : 0) + (user ? 2 : 0) + (addr ? 2 : 0) + (laddr ? 2 : 0)
+ (skipme ? 2 : 0), "CLIENT");
REDIS_CMD_APPEND_SSTR_STATIC(cmdstr, "KILL");
if (address != NULL) {
redis_cmd_append_sstr(cmdstr, Z_STRVAL_P(address), Z_STRLEN_P(address));
}
if (id != NULL) {
REDIS_CMD_APPEND_SSTR_STATIC(cmdstr, "ID");
redis_cmd_append_sstr(cmdstr, Z_STRVAL_P(id), Z_STRLEN_P(id));
}
if (type != NULL) {
REDIS_CMD_APPEND_SSTR_STATIC(cmdstr, "TYPE");
redis_cmd_append_sstr(cmdstr, Z_STRVAL_P(type), Z_STRLEN_P(type));
}
if (user != NULL) {
REDIS_CMD_APPEND_SSTR_STATIC(cmdstr, "USER");
redis_cmd_append_sstr(cmdstr, Z_STRVAL_P(user), Z_STRLEN_P(user));
}
if (addr != NULL) {
REDIS_CMD_APPEND_SSTR_STATIC(cmdstr, "ADDR");
redis_cmd_append_sstr(cmdstr, Z_STRVAL_P(addr), Z_STRLEN_P(addr));
}
if (laddr != NULL) {
REDIS_CMD_APPEND_SSTR_STATIC(cmdstr, "LADDR");
redis_cmd_append_sstr(cmdstr, Z_STRVAL_P(laddr), Z_STRLEN_P(laddr));
}
if (skipme != NULL) {
REDIS_CMD_APPEND_SSTR_STATIC(cmdstr, "SKIPME");
redis_cmd_append_sstr(cmdstr, Z_STRVAL_P(skipme), Z_STRLEN_P(skipme));
}
return SUCCESS;
}
static int
redis_build_client_tracking_command(smart_string *cmdstr, int argc, zval *z_args)
{
zend_string *zkey;
zval *z_ele, *redirect = NULL, *prefix = NULL;
zend_bool bcast = 0, optin = 0, optout = 0, noloop = 0;
if (argc < 1) {
return FAILURE;
}
if (argc > 1) {
if (Z_TYPE(z_args[1]) != IS_ARRAY) {
return FAILURE;
}
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL(z_args[1]), zkey, z_ele) {
if (zkey != NULL) {
ZVAL_DEREF(z_ele);
if (zend_string_equals_literal_ci(zkey, "redirect")) {
if (Z_TYPE_P(z_ele) != IS_STRING) {
return FAILURE;
}
redirect = z_ele;
} else if (zend_string_equals_literal_ci(zkey, "prefix")) {
if (Z_TYPE_P(z_ele) != IS_STRING && Z_TYPE_P(z_ele) != IS_ARRAY) {
return FAILURE;
}
prefix = z_ele;
} else if (zend_string_equals_literal_ci(zkey, "bcast")) {
bcast = zval_is_true(z_ele);
} else if (zend_string_equals_literal_ci(zkey, "optin")) {
optin = zval_is_true(z_ele);
} else if (zend_string_equals_literal_ci(zkey, "optout")) {
optout = zval_is_true(z_ele);
} else if (zend_string_equals_literal_ci(zkey, "noloop")) {
noloop = zval_is_true(z_ele);
}
}
} ZEND_HASH_FOREACH_END();
}
REDIS_CMD_INIT_SSTR_STATIC(cmdstr, 2 + (redirect ? 2 : 0)
+ (prefix ? 2 * zend_hash_num_elements(Z_ARRVAL_P(prefix)) : 0)
+ bcast + optin + optout + noloop, "CLIENT");
REDIS_CMD_APPEND_SSTR_STATIC(cmdstr, "TRACKING");
if (Z_TYPE(z_args[0]) == IS_STRING && (
ZVAL_STRICMP_STATIC(&z_args[0], "on") ||
ZVAL_STRICMP_STATIC(&z_args[0], "off")
)) {
redis_cmd_append_sstr(cmdstr, Z_STRVAL(z_args[0]), Z_STRLEN(z_args[0]));
} else if (zval_is_true(&z_args[0])) {
REDIS_CMD_APPEND_SSTR_STATIC(cmdstr, "ON");
} else {
REDIS_CMD_APPEND_SSTR_STATIC(cmdstr, "OFF");
}
if (redirect != NULL) {
REDIS_CMD_APPEND_SSTR_STATIC(cmdstr, "REDIRECT");
redis_cmd_append_sstr(cmdstr, Z_STRVAL_P(redirect), Z_STRLEN_P(redirect));
}
if (prefix != NULL) {
if (Z_TYPE_P(prefix) == IS_ARRAY) {
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(prefix), z_ele) {
REDIS_CMD_APPEND_SSTR_STATIC(cmdstr, "PREFIX");
if (Z_TYPE_P(z_ele) == IS_STRING) {
redis_cmd_append_sstr(cmdstr, Z_STRVAL_P(z_ele), Z_STRLEN_P(z_ele));
} else {
zkey = zval_get_string(z_ele);
redis_cmd_append_sstr(cmdstr, ZSTR_VAL(zkey), ZSTR_LEN(zkey));
zend_string_release(zkey);
}
} ZEND_HASH_FOREACH_END();
} else {
REDIS_CMD_APPEND_SSTR_STATIC(cmdstr, "PREFIX");
redis_cmd_append_sstr(cmdstr, Z_STRVAL_P(prefix), Z_STRLEN_P(prefix));
}
}
if (bcast) {
REDIS_CMD_APPEND_SSTR_STATIC(cmdstr, "BCAST");
}
if (optin) {
REDIS_CMD_APPEND_SSTR_STATIC(cmdstr, "OPTIN");
}
if (optout) {
REDIS_CMD_APPEND_SSTR_STATIC(cmdstr, "OPTOUT");
}
if (noloop) {
REDIS_CMD_APPEND_SSTR_STATIC(cmdstr, "NOLOOP");
}
return SUCCESS;
}
int
redis_client_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
smart_string cmdstr = {0};
zend_string *op = NULL;
zval *z_args = NULL;
int argc = 0;
ZEND_PARSE_PARAMETERS_START(1, -1)
Z_PARAM_STR(op)
Z_PARAM_OPTIONAL
Z_PARAM_VARIADIC('*', z_args, argc)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
if (zend_string_equals_literal_ci(op, "INFO")) {
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 1, "CLIENT");
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "INFO");
} else if (zend_string_equals_literal_ci(op, "LIST")) {
if (redis_build_client_list_command(&cmdstr, argc, z_args) != 0) {
return FAILURE;
}
*ctx = PHPREDIS_CTX_PTR;
} else if (zend_string_equals_literal_ci(op, "CACHING")) {
if (argc < 1) {
return FAILURE;
}
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 2, "CLIENT");
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "CACHING");
if (Z_TYPE(z_args[0]) == IS_STRING && (
ZVAL_STRICMP_STATIC(&z_args[0], "yes") ||
ZVAL_STRICMP_STATIC(&z_args[0], "no")
)) {
redis_cmd_append_sstr(&cmdstr, Z_STRVAL(z_args[0]), Z_STRLEN(z_args[0]));
} else if (zval_is_true(&z_args[0])) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "YES");
} else {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "NO");
}
*ctx = PHPREDIS_CTX_PTR + 1;
} else if (zend_string_equals_literal_ci(op, "GETNAME")) {
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 1, "CLIENT");
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "GETNAME");
*ctx = PHPREDIS_CTX_PTR + 3;
} else if (zend_string_equals_literal_ci(op, "GETREDIR") || zend_string_equals_literal_ci(op, "ID")) {
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 1, "CLIENT");
redis_cmd_append_sstr(&cmdstr, ZSTR_VAL(op), ZSTR_LEN(op));
*ctx = PHPREDIS_CTX_PTR + 2;
} else if (zend_string_equals_literal_ci(op, "KILL")) {
if (redis_build_client_kill_command(&cmdstr, argc, z_args) != 0) {
return FAILURE;
}
*ctx = PHPREDIS_CTX_PTR + 1;
} else if (zend_string_equals_literal_ci(op, "NO-EVICT")) {
if (argc < 1) {
return FAILURE;
}
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 2, "CLIENT");
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "NO-EVICT");
if (Z_TYPE(z_args[0]) == IS_STRING && (
ZVAL_STRICMP_STATIC(&z_args[0], "on") ||
ZVAL_STRICMP_STATIC(&z_args[0], "off")
)) {
redis_cmd_append_sstr(&cmdstr, Z_STRVAL(z_args[0]), Z_STRLEN(z_args[0]));
} else if (zval_is_true(&z_args[0])) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "ON");
} else {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "OFF");
}
*ctx = PHPREDIS_CTX_PTR + 1;
} else if (zend_string_equals_literal_ci(op, "PAUSE")) {
if (argc < 1 || Z_TYPE(z_args[0]) != IS_LONG || (
argc > 1 && (
Z_TYPE(z_args[1]) != IS_STRING || (
!ZVAL_STRICMP_STATIC(&z_args[1], "write") &&
!ZVAL_STRICMP_STATIC(&z_args[1], "all")
)
)
)) {
return FAILURE;
}
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc > 1 ? 3 : 2, "CLIENT");
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "PAUSE");
redis_cmd_append_sstr_long(&cmdstr, Z_LVAL(z_args[0]));
if (argc > 1) {
redis_cmd_append_sstr(&cmdstr, Z_STRVAL(z_args[1]), Z_STRLEN(z_args[1]));
}
*ctx = PHPREDIS_CTX_PTR + 1;
} else if (zend_string_equals_literal_ci(op, "REPLY")) {
if (argc > 0 && (
Z_TYPE(z_args[0]) != IS_STRING || (
!ZVAL_STRICMP_STATIC(&z_args[0], "on") &&
!ZVAL_STRICMP_STATIC(&z_args[0], "off") &&
!ZVAL_STRICMP_STATIC(&z_args[0], "skip")
)
)) {
return FAILURE;
}
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc > 0 ? 2 : 1, "CLIENT");
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "REPLY");
if (argc > 0) {
redis_cmd_append_sstr(&cmdstr, Z_STRVAL(z_args[0]), Z_STRLEN(z_args[0]));
}
*ctx = PHPREDIS_CTX_PTR + 1;
} else if (zend_string_equals_literal_ci(op, "SETNAME")) {
if (argc < 1 || Z_TYPE(z_args[0]) != IS_STRING) {
return FAILURE;
}
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 2, "CLIENT");
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "SETNAME");
redis_cmd_append_sstr(&cmdstr, Z_STRVAL(z_args[0]), Z_STRLEN(z_args[0]));
*ctx = PHPREDIS_CTX_PTR + 1;
} else if (zend_string_equals_literal_ci(op, "TRACKING")) {
if (redis_build_client_tracking_command(&cmdstr, argc, z_args) != 0) {
return FAILURE;
}
*ctx = PHPREDIS_CTX_PTR + 1;
} else if (zend_string_equals_literal_ci(op, "TRACKINGINFO")) {
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 1, "CLIENT");
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "TRACKINGINFO");
*ctx = PHPREDIS_CTX_PTR + 4;
} else if (zend_string_equals_literal_ci(op, "UNBLOCK")) {
if (argc < 1 || Z_TYPE(z_args[0]) != IS_STRING || (
argc > 1 && (
Z_TYPE(z_args[1]) != IS_STRING || (
!ZVAL_STRICMP_STATIC(&z_args[1], "timeout") &&
!ZVAL_STRICMP_STATIC(&z_args[1], "error")
)
)
)) {
return FAILURE;
}
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc > 1 ? 3 : 2, "CLIENT");
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "UNBLOCK");
redis_cmd_append_sstr(&cmdstr, Z_STRVAL(z_args[0]), Z_STRLEN(z_args[0]));
if (argc > 1) {
redis_cmd_append_sstr(&cmdstr, Z_STRVAL(z_args[1]), Z_STRLEN(z_args[1]));
}
*ctx = PHPREDIS_CTX_PTR + 2;
} else if (zend_string_equals_literal_ci(op, "UNPAUSE")) {
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 2, "CLIENT");
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "UNPAUSE");
*ctx = PHPREDIS_CTX_PTR + 1;
} else {
return FAILURE;
}
// Push out values
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* COMMAND */
int redis_command_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
smart_string cmdstr = {0};
zend_string *op = NULL, *zstr;
zval *z_args = NULL;
int i, argc = 0;
ZEND_PARSE_PARAMETERS_START(0, -1)
Z_PARAM_OPTIONAL
Z_PARAM_STR(op)
Z_PARAM_VARIADIC('*', z_args, argc)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
if (op == NULL) {
*ctx = NULL;
argc = 0;
} else if (zend_string_equals_literal_ci(op, "COUNT")) {
*ctx = PHPREDIS_CTX_PTR;
argc = 0;
} else if (zend_string_equals_literal_ci(op, "DOCS") ||
zend_string_equals_literal_ci(op, "INFO")
) {
*ctx = NULL;
} else if (zend_string_equals_literal_ci(op, "GETKEYS") ||
zend_string_equals_literal_ci(op, "LIST")
) {
*ctx = PHPREDIS_CTX_PTR + 1;
} else if (zend_string_equals_literal_ci(op, "GETKEYSANDFLAGS")) {
*ctx = PHPREDIS_CTX_PTR + 2;
} else {
php_error_docref(NULL, E_WARNING, "Unknown COMMAND operation '%s'", ZSTR_VAL(op));
return FAILURE;
}
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, !!op + argc, "COMMAND");
if (op) redis_cmd_append_sstr_zstr(&cmdstr, op);
for (i = 0; i < argc; ++i) {
zstr = zval_get_string(&z_args[i]);
redis_cmd_append_sstr(&cmdstr, ZSTR_VAL(zstr), ZSTR_LEN(zstr));
zend_string_release(zstr);
}
// Push out values
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
/* Any slot will do */
CMD_RAND_SLOT(slot);
return SUCCESS;
}
int
redis_copy_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
zend_string *src = NULL, *dst = NULL;
smart_string cmdstr = {0};
HashTable *opts = NULL;
zend_bool replace = 0;
zend_string *zkey;
zend_long db = -1;
short slot2;
zval *zv;
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STR(src)
Z_PARAM_STR(dst)
Z_PARAM_OPTIONAL
Z_PARAM_ARRAY_HT_OR_NULL(opts)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
if (opts != NULL) {
ZEND_HASH_FOREACH_STR_KEY_VAL(opts, zkey, zv) {
if (zkey == NULL)
continue;
ZVAL_DEREF(zv);
if (zend_string_equals_literal_ci(zkey, "db")) {
db = zval_get_long(zv);
} else if (zend_string_equals_literal_ci(zkey, "replace")) {
replace = zval_is_true(zv);
}
} ZEND_HASH_FOREACH_END();
}
if (slot && db != -1) {
php_error_docref(NULL, E_WARNING, "Cant copy to a specific DB in cluster mode");
return FAILURE;
}
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 2 + (db > -1 ? 2 : 0) + replace, "COPY");
redis_cmd_append_sstr_key_zstr(&cmdstr, src, redis_sock, slot);
redis_cmd_append_sstr_key_zstr(&cmdstr, dst, redis_sock, slot ? &slot2 : NULL);
if (slot && *slot != slot2) {
php_error_docref(NULL, E_WARNING, "Keys must hash to the same slot!");
efree(cmdstr.c);
return FAILURE;
}
if (db > -1) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "DB");
redis_cmd_append_sstr_long(&cmdstr, db);
}
REDIS_CMD_APPEND_SSTR_OPT_STATIC(&cmdstr, replace, "REPLACE");
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* XADD */
int redis_xadd_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
smart_string cmdstr = {0};
zend_string *arrkey;
zval *z_fields, *value;
zend_long maxlen = 0;
zend_bool approx = 0, nomkstream = 0;
zend_ulong idx;
HashTable *ht_fields;
int fcount, argc;
char *key, *id;
size_t keylen, idlen;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssa|lbb", &key, &keylen,
&id, &idlen, &z_fields, &maxlen, &approx,
&nomkstream) == FAILURE)
{
return FAILURE;
}
/* At least one field and string are required */
ht_fields = Z_ARRVAL_P(z_fields);
if ((fcount = zend_hash_num_elements(ht_fields)) == 0) {
return FAILURE;
}
if (maxlen < 0 || (maxlen == 0 && approx != 0)) {
php_error_docref(NULL, E_WARNING,
"Warning: Invalid MAXLEN argument or approximate flag");
}
/* Calculate argc for XADD. It's a bit complex because we've got
* an optional MAXLEN argument which can either take the form MAXLEN N
* or MAXLEN ~ N */
argc = 2 + nomkstream + (fcount * 2) + (maxlen > 0 ? (approx ? 3 : 2) : 0);
/* XADD key ID field string [field string ...] */
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc, "XADD");
redis_cmd_append_sstr_key(&cmdstr, key, keylen, redis_sock, slot);
if (nomkstream) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "NOMKSTREAM");
}
/* Now append our MAXLEN bits if we've got them */
if (maxlen > 0) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "MAXLEN");
REDIS_CMD_APPEND_SSTR_OPT_STATIC(&cmdstr, approx, "~");
redis_cmd_append_sstr_long(&cmdstr, maxlen);
}
/* Now append ID and field(s) */
redis_cmd_append_sstr(&cmdstr, id, idlen);
ZEND_HASH_FOREACH_KEY_VAL(ht_fields, idx, arrkey, value) {
redis_cmd_append_sstr_arrkey(&cmdstr, arrkey, idx);
redis_cmd_append_sstr_zval(&cmdstr, value, redis_sock);
} ZEND_HASH_FOREACH_END();
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
// XPENDING key group [start end count [consumer] [idle]]
int redis_xpending_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
zend_string *key = NULL, *group = NULL, *start = NULL, *end = NULL,
*consumer = NULL;
zend_long count = -1, idle = 0;
smart_string cmdstr = {0};
int argc;
ZEND_PARSE_PARAMETERS_START(2, 7)
Z_PARAM_STR(key)
Z_PARAM_STR(group)
Z_PARAM_OPTIONAL
Z_PARAM_STR_OR_NULL(start)
Z_PARAM_STR_OR_NULL(end)
Z_PARAM_LONG(count)
Z_PARAM_STR_OR_NULL(consumer)
Z_PARAM_LONG(idle)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
/* If we've been passed a start argument, we also need end and count */
if (start != NULL && (end == NULL || count < 0)) {
php_error_docref(NULL, E_WARNING, "'$start' must be accompanied by '$end' and '$count' arguments");
return FAILURE;
}
/* Calculate argc. It's either 2, 5, 6 or 7 */
argc = 2 + (start != NULL ? 3 + (consumer != NULL) + (idle != 0) : 0);
/* Construct command and add required arguments */
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc, "XPENDING");
redis_cmd_append_sstr_key_zstr(&cmdstr, key, redis_sock, slot);
redis_cmd_append_sstr_zstr(&cmdstr, group);
/* Add optional argumentst */
if (start) {
if (idle != 0) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "IDLE");
redis_cmd_append_sstr_long(&cmdstr, (long)idle);
}
redis_cmd_append_sstr_zstr(&cmdstr, start);
redis_cmd_append_sstr_zstr(&cmdstr, end);
redis_cmd_append_sstr_long(&cmdstr, (long)count);
/* Finally add consumer if we have it */
if (consumer) redis_cmd_append_sstr_zstr(&cmdstr, consumer);
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* X[REV]RANGE key start end [COUNT count] */
int redis_xrange_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
smart_string cmdstr = {0};
char *key, *start, *end;
size_t keylen, startlen, endlen;
zend_long count = -1;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|l", &key, &keylen,
&start, &startlen, &end, &endlen, &count)
== FAILURE)
{
return FAILURE;
}
redis_cmd_init_sstr(&cmdstr, 3 + (2 * (count > -1)), kw, strlen(kw));
redis_cmd_append_sstr_key(&cmdstr, key, keylen, redis_sock, slot);
redis_cmd_append_sstr(&cmdstr, start, startlen);
redis_cmd_append_sstr(&cmdstr, end, endlen);
if (count > -1) {
redis_cmd_append_sstr(&cmdstr, ZEND_STRL("COUNT"));
redis_cmd_append_sstr_long(&cmdstr, count);
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* Helper function to take an associative array and append the Redis
* STREAMS stream [stream...] id [id ...] arguments to a command string. */
static int
append_stream_args(smart_string *cmdstr, HashTable *ht, RedisSock *redis_sock,
short *slot)
{
char *kptr, kbuf[40];
int klen, i, pos = 0;
zend_string *key, *idstr;
short oldslot = -1;
zval **id;
zend_ulong idx;
/* Append STREAM qualifier */
REDIS_CMD_APPEND_SSTR_STATIC(cmdstr, "STREAMS");
/* Allocate memory to keep IDs */
id = emalloc(sizeof(*id) * zend_hash_num_elements(ht));
/* Iterate over our stream => id array appending streams and retaining each
* value for final arguments */
ZEND_HASH_FOREACH_KEY_VAL(ht, idx, key, id[pos++]) {
if (key) {
klen = ZSTR_LEN(key);
kptr = ZSTR_VAL(key);
} else {
klen = snprintf(kbuf, sizeof(kbuf), "%ld", (long)idx);
kptr = (char*)kbuf;
}
/* Append stream key */
redis_cmd_append_sstr_key(cmdstr, kptr, klen, redis_sock, slot);
/* Protect the user against CROSSSLOT to avoid confusion */
if (slot) {
if (oldslot != -1 && *slot != oldslot) {
php_error_docref(NULL, E_WARNING,
"Warning, not all keys hash to the same slot!");
efree(id);
return FAILURE;
}
oldslot = *slot;
}
} ZEND_HASH_FOREACH_END();
/* Add our IDs */
for (i = 0; i < pos; i++) {
idstr = zval_get_string(id[i]);
redis_cmd_append_sstr(cmdstr, ZSTR_VAL(idstr), ZSTR_LEN(idstr));
zend_string_release(idstr);
}
/* Clean up ID container array */
efree(id);
return 0;
}
/* XREAD [COUNT count] [BLOCK ms] STREAMS key [key ...] id [id ...] */
int redis_xread_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
smart_string cmdstr = {0};
zend_long count = -1, block = -1;
zval *z_streams;
int argc, scount;
HashTable *kt;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|ll", &z_streams,
&count, &block) == FAILURE)
{
return FAILURE;
}
/* At least one stream and ID is required */
kt = Z_ARRVAL_P(z_streams);
if ((scount = zend_hash_num_elements(kt)) < 1) {
return FAILURE;
}
/* Calculate argc and start constructing command */
argc = 1 + (2 * scount) + (2 * (count > -1)) + (2 * (block > -1));
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc, "XREAD");
/* Append COUNT if we have it */
if (count > -1) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "COUNT");
redis_cmd_append_sstr_long(&cmdstr, count);
}
/* Append BLOCK if we have it */
if (block > -1) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "BLOCK");
redis_cmd_append_sstr_long(&cmdstr, block);
}
/* Append final STREAM key [key ...] id [id ...] arguments */
if (append_stream_args(&cmdstr, kt, redis_sock, slot) < 0) {
efree(cmdstr.c);
return FAILURE;
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* XREADGROUP GROUP group consumer [COUNT count] [BLOCK ms]
* STREAMS key [key ...] id [id ...] */
int redis_xreadgroup_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
smart_string cmdstr = {0};
zval *z_streams;
HashTable *kt;
char *group, *consumer;
size_t grouplen, consumerlen;
int scount, argc;
zend_long count, block;
zend_bool no_count = 1, no_block = 1;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssa|l!l!", &group,
&grouplen, &consumer, &consumerlen, &z_streams,
&count, &no_count, &block, &no_block) == FAILURE)
{
return FAILURE;
}
/* Negative COUNT or BLOCK is illegal so abort immediately */
if ((!no_count && count < 0) || (!no_block && block < 0)) {
php_error_docref(NULL, E_WARNING, "Negative values for COUNT or BLOCK are illegal.");
return FAILURE;
}
/* Redis requires at least one stream */
kt = Z_ARRVAL_P(z_streams);
if ((scount = zend_hash_num_elements(kt)) < 1) {
return FAILURE;
}
/* Calculate argc and start constructing commands */
argc = 4 + (2 * scount) + (2 * !no_count) + (2 * !no_block);
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc, "XREADGROUP");
/* Group and consumer */
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "GROUP");
redis_cmd_append_sstr(&cmdstr, group, grouplen);
redis_cmd_append_sstr(&cmdstr, consumer, consumerlen);
/* Append COUNT if we have it */
if (!no_count) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "COUNT");
redis_cmd_append_sstr_long(&cmdstr, count);
}
/* Append BLOCK argument if we have it */
if (!no_block) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "BLOCK");
redis_cmd_append_sstr_long(&cmdstr, block);
}
/* Finally append stream and id args */
if (append_stream_args(&cmdstr, kt, redis_sock, slot) < 0) {
efree(cmdstr.c);
return FAILURE;
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* XACK key group id [id ...] */
int redis_xack_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
smart_string cmdstr = {0};
char *key, *group;
size_t keylen, grouplen;
zend_string *idstr;
zval *z_ids, *z_id;
HashTable *ht_ids;
int idcount;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssa", &key, &keylen,
&group, &grouplen, &z_ids) == FAILURE)
{
return FAILURE;
}
ht_ids = Z_ARRVAL_P(z_ids);
if ((idcount = zend_hash_num_elements(ht_ids)) < 1) {
return FAILURE;
}
/* Create command and add initial arguments */
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 2 + idcount, "XACK");
redis_cmd_append_sstr_key(&cmdstr, key, keylen, redis_sock, slot);
redis_cmd_append_sstr(&cmdstr, group, grouplen);
/* Append IDs */
ZEND_HASH_FOREACH_VAL(ht_ids, z_id) {
idstr = zval_get_string(z_id);
redis_cmd_append_sstr(&cmdstr, ZSTR_VAL(idstr), ZSTR_LEN(idstr));
zend_string_release(idstr);
} ZEND_HASH_FOREACH_END();
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* XCLAIM options container */
typedef struct xclaimOptions {
struct {
char *type;
int64_t time;
} idle;
zend_long retrycount;
int force;
int justid;
} xclaimOptions;
/* Attempt to extract an int64_t from the provided zval */
static int zval_get_i64(zval *zv, int64_t *retval) {
if (Z_TYPE_P(zv) == IS_LONG) {
*retval = (int64_t)Z_LVAL_P(zv);
return SUCCESS;
} else if (Z_TYPE_P(zv) == IS_DOUBLE) {
*retval = (int64_t)Z_DVAL_P(zv);
return SUCCESS;
} else if (Z_TYPE_P(zv) == IS_STRING) {
zend_long lval;
double dval;
switch (is_numeric_string(Z_STRVAL_P(zv), Z_STRLEN_P(zv), &lval, &dval, 1)) {
case IS_LONG:
*retval = (int64_t)lval;
return SUCCESS;
case IS_DOUBLE:
*retval = (int64_t)dval;
return SUCCESS;
}
}
/* If we make it here we have failed */
return FAILURE;
}
/* Helper function to get an integer XCLAIM argument. This can overflow a
* 32-bit PHP long so we have to extract it as an int64_t. If the value is
* not a valid number or negative, we'll inform the user of the problem and
* that the argument is being ignored. */
static int64_t get_xclaim_i64_arg(const char *key, zval *zv) {
int64_t retval = -1;
/* Extract an i64, and if we can't let the user know there is an issue. */
if (zval_get_i64(zv, &retval) == FAILURE || retval < 0) {
php_error_docref(NULL, E_WARNING,
"Invalid XCLAIM option '%s' will be ignored", key);
}
return retval;
}
/* Helper to extract XCLAIM options */
static void get_xclaim_options(zval *z_arr, xclaimOptions *opt) {
zend_string *zkey;
HashTable *ht;
zval *zv;
/* Initialize options array to sane defaults */
memset(opt, 0, sizeof(*opt));
opt->retrycount = -1;
opt->idle.time = -1;
/* Early return if we don't have any options */
if (z_arr == NULL)
return;
/* Iterate over our options array */
ht = Z_ARRVAL_P(z_arr);
ZEND_HASH_FOREACH_STR_KEY_VAL(ht, zkey, zv) {
if (zkey) {
if (zend_string_equals_literal_ci(zkey, "TIME")) {
opt->idle.type = "TIME";
opt->idle.time = get_xclaim_i64_arg("TIME", zv);
} else if (zend_string_equals_literal_ci(zkey, "IDLE")) {
opt->idle.type = "IDLE";
opt->idle.time = get_xclaim_i64_arg("IDLE", zv);
} else if (zend_string_equals_literal_ci(zkey, "RETRYCOUNT")) {
opt->retrycount = zval_get_long(zv);
}
} else if (Z_TYPE_P(zv) == IS_STRING) {
if (zend_string_equals_literal_ci(Z_STR_P(zv), "FORCE")) {
opt->force = 1;
} else if (zend_string_equals_literal_ci(Z_STR_P(zv), "JUSTID")) {
opt->justid = 1;
}
}
} ZEND_HASH_FOREACH_END();
}
/* Count argc for any options we may have */
static int xclaim_options_argc(xclaimOptions *opt) {
int argc = 0;
if (opt->idle.type != NULL && opt->idle.time != -1)
argc += 2;
if (opt->retrycount != -1)
argc += 2;
if (opt->force)
argc++;
if (opt->justid)
argc++;
return argc;
}
/* Append XCLAIM options */
static void append_xclaim_options(smart_string *cmd, xclaimOptions *opt) {
/* IDLE/TIME long */
if (opt->idle.type != NULL && opt->idle.time != -1) {
redis_cmd_append_sstr(cmd, opt->idle.type, strlen(opt->idle.type));
redis_cmd_append_sstr_i64(cmd, opt->idle.time);
}
/* RETRYCOUNT */
if (opt->retrycount != -1) {
REDIS_CMD_APPEND_SSTR_STATIC(cmd, "RETRYCOUNT");
redis_cmd_append_sstr_long(cmd, opt->retrycount);
}
/* FORCE and JUSTID */
if (opt->force)
REDIS_CMD_APPEND_SSTR_STATIC(cmd, "FORCE");
if (opt->justid)
REDIS_CMD_APPEND_SSTR_STATIC(cmd, "JUSTID");
}
int
redis_xautoclaim_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
smart_string cmdstr = {0};
char *key, *group, *consumer, *start;
size_t keylen, grouplen, consumerlen, startlen;
zend_long min_idle, count = -1;
zend_bool justid = 0;
int argc;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sssls|lb", &key, &keylen,
&group, &grouplen, &consumer, &consumerlen,
&min_idle, &start, &startlen, &count, &justid
) == FAILURE)
{
return FAILURE;
}
argc = 5 + (count > 0 ? 1 + count : 0) + justid;
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc, "XAUTOCLAIM");
redis_cmd_append_sstr_key(&cmdstr, key, keylen, redis_sock, slot);
redis_cmd_append_sstr(&cmdstr, group, grouplen);
redis_cmd_append_sstr(&cmdstr, consumer, consumerlen);
redis_cmd_append_sstr_long(&cmdstr, min_idle);
redis_cmd_append_sstr(&cmdstr, start, startlen);
if (count > 0) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "COUNT");
redis_cmd_append_sstr_long(&cmdstr, count);
}
if (justid) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "JUSTID");
}
// Set the context to distinguish XCLAIM from XAUTOCLAIM which
// have slightly different reply structures.
*ctx = PHPREDIS_CTX_PTR;
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* XCLAIM
[IDLE ] [TIME ] [RETRYCOUNT ]
[FORCE] [JUSTID] */
int redis_xclaim_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
smart_string cmdstr = {0};
char *key, *group, *consumer;
size_t keylen, grouplen, consumerlen;
zend_long min_idle;
int argc, id_count;
zval *z_ids, *z_id, *z_opts = NULL;
zend_string *zstr;
HashTable *ht_ids;
xclaimOptions opts;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sssla|a", &key, &keylen,
&group, &grouplen, &consumer, &consumerlen, &min_idle,
&z_ids, &z_opts) == FAILURE)
{
return FAILURE;
}
/* At least one id is required */
ht_ids = Z_ARRVAL_P(z_ids);
if ((id_count = zend_hash_num_elements(ht_ids)) < 1) {
return FAILURE;
}
/* Extract options array if we've got them */
get_xclaim_options(z_opts, &opts);
/* Now we have enough information to calculate argc */
argc = 4 + id_count + xclaim_options_argc(&opts);
/* Start constructing our command */
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc, "XCLAIM");
redis_cmd_append_sstr_key(&cmdstr, key, keylen, redis_sock, slot);
redis_cmd_append_sstr(&cmdstr, group, grouplen);
redis_cmd_append_sstr(&cmdstr, consumer, consumerlen);
redis_cmd_append_sstr_long(&cmdstr, min_idle);
/* Add IDs */
ZEND_HASH_FOREACH_VAL(ht_ids, z_id) {
zstr = zval_get_string(z_id);
redis_cmd_append_sstr(&cmdstr, ZSTR_VAL(zstr), ZSTR_LEN(zstr));
zend_string_release(zstr);
} ZEND_HASH_FOREACH_END();
/* Finally add our options */
append_xclaim_options(&cmdstr, &opts);
/* Success */
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* XGROUP HELP
* XGROUP CREATE key group id [MKSTREAM] [ENTRIESREAD ]
* XGROUP SETID key group id [ENTRIESREAD ]
* XGROUP CREATECONSUMER key group consumer
* XGROUP DELCONSUMER key group consumer
* XGROUP DESTROY key group
*/
int redis_xgroup_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
zend_string *op = NULL, *key = NULL, *group = NULL, *id_or_consumer = NULL;
int nargs, is_create = 0, is_setid = 0;
zend_long entries_read = -2;
smart_string cmdstr = {0};
zend_bool mkstream = 0;
ZEND_PARSE_PARAMETERS_START(1, 6)
Z_PARAM_STR(op)
Z_PARAM_OPTIONAL
Z_PARAM_STR(key)
Z_PARAM_STR(group)
Z_PARAM_STR(id_or_consumer)
Z_PARAM_BOOL(mkstream)
Z_PARAM_LONG(entries_read)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
if (zend_string_equals_literal_ci(op, "HELP")) {
nargs = 0;
} else if ((is_create = zend_string_equals_literal_ci(op, "CREATE")) ||
(is_setid = zend_string_equals_literal_ci(op, "SETID")) ||
zend_string_equals_literal_ci(op, "CREATECONSUMER") ||
zend_string_equals_literal_ci(op, "DELCONSUMER"))
{
nargs = 3;
} else if (zend_string_equals_literal_ci(op, "DESTROY")) {
nargs = 2;
} else {
php_error_docref(NULL, E_WARNING, "Unknown XGROUP operation '%s'", ZSTR_VAL(op));
return FAILURE;
}
if (ZEND_NUM_ARGS() < nargs) {
php_error_docref(NULL, E_WARNING, "Operation '%s' requires %d arguments", ZSTR_VAL(op), nargs);
return FAILURE;
}
mkstream &= is_create;
if (!(is_create || is_setid))
entries_read = -2;
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 1 + nargs + !!mkstream + (entries_read != -2 ? 2 : 0), "XGROUP");
redis_cmd_append_sstr_zstr(&cmdstr, op);
if (nargs-- > 0) redis_cmd_append_sstr_key_zstr(&cmdstr, key, redis_sock, slot);
if (nargs-- > 0) redis_cmd_append_sstr_zstr(&cmdstr, group);
if (nargs-- > 0) redis_cmd_append_sstr_zstr(&cmdstr, id_or_consumer);
REDIS_CMD_APPEND_SSTR_OPT_STATIC(&cmdstr, !!mkstream, "MKSTREAM");
if (entries_read != -2) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "ENTRIESREAD");
redis_cmd_append_sstr_long(&cmdstr, entries_read);
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* XINFO CONSUMERS key group
* XINFO GROUPS key
* XINFO STREAM key [FULL [COUNT N]]
* XINFO HELP */
int redis_xinfo_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
zend_string *op = NULL, *key = NULL, *arg = NULL;
smart_string cmdstr = {0};
zend_long count = -1;
ZEND_PARSE_PARAMETERS_START(1, 4)
Z_PARAM_STR(op)
Z_PARAM_OPTIONAL
Z_PARAM_STR_OR_NULL(key)
Z_PARAM_STR_OR_NULL(arg)
Z_PARAM_LONG(count)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
if ((arg != NULL && key == NULL) || (count != -1 && (key == NULL || arg == NULL))) {
php_error_docref(NULL, E_WARNING, "Cannot pass a non-null optional argument after a NULL one.");
return FAILURE;
}
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 1 + (key != NULL) + (arg != NULL) + (count > -1 ? 2 : 0), "XINFO");
redis_cmd_append_sstr_zstr(&cmdstr, op);
if (key != NULL)
redis_cmd_append_sstr_key(&cmdstr, ZSTR_VAL(key), ZSTR_LEN(key), redis_sock, slot);
if (arg != NULL)
redis_cmd_append_sstr_zstr(&cmdstr, arg);
if (count > -1) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "COUNT");
redis_cmd_append_sstr_long(&cmdstr, count);
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
// XTRIM key [= | ~] threshold [LIMIT count]
int redis_xtrim_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
zend_string *key = NULL, *threshold = NULL;
zend_bool approx = 0, minid = 0;
smart_string cmdstr = {0};
zend_long limit = -1;
int argc;
ZEND_PARSE_PARAMETERS_START(2, 5)
Z_PARAM_STR(key)
Z_PARAM_STR(threshold)
Z_PARAM_OPTIONAL
Z_PARAM_BOOL(approx)
Z_PARAM_BOOL(minid)
Z_PARAM_LONG(limit)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
argc = 4 + (approx && limit > -1 ? 2 : 0);
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc, "XTRIM");
redis_cmd_append_sstr_key_zstr(&cmdstr, key, redis_sock, slot);
if (minid) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "MINID");
} else {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "MAXLEN");
}
if (approx) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "~");
} else {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "=");
}
redis_cmd_append_sstr_zstr(&cmdstr, threshold);
if (limit > -1 && approx) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "LIMIT");
redis_cmd_append_sstr_long(&cmdstr, limit);
} else if (limit > -1) {
php_error_docref(NULL, E_WARNING, "Cannot use LIMIT without an approximate match, ignoring");
} else if (ZEND_NUM_ARGS() == 5) {
php_error_docref(NULL, E_WARNING, "Limit must be >= 0");
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
// [P]EXPIRE[AT] [NX | XX | GT | LT]
int redis_expire_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx)
{
zend_string *key = NULL, *mode = NULL;
smart_string cmdstr = {0};
zend_long timeout = 0;
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STR(key)
Z_PARAM_LONG(timeout)
Z_PARAM_OPTIONAL
Z_PARAM_STR_OR_NULL(mode)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
if (mode != NULL && !(zend_string_equals_literal_ci(mode, "NX") ||
zend_string_equals_literal_ci(mode, "XX") ||
zend_string_equals_literal_ci(mode, "LT") ||
zend_string_equals_literal_ci(mode, "GT")))
{
php_error_docref(NULL, E_WARNING, "Unknown expiration modifier '%s'", ZSTR_VAL(mode));
return FAILURE;
}
redis_cmd_init_sstr(&cmdstr, 2 + (mode != NULL), kw, strlen(kw));
redis_cmd_append_sstr_key_zstr(&cmdstr, key, redis_sock, slot);
redis_cmd_append_sstr_long(&cmdstr, timeout);
if (mode != NULL) redis_cmd_append_sstr_zstr(&cmdstr, mode);
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
int
redis_sentinel_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx)
{
if (zend_parse_parameters_none() == FAILURE) {
return FAILURE;
}
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "SENTINEL", "s", kw, strlen(kw));
return SUCCESS;
}
int
redis_sentinel_str_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx)
{
zend_string *name;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
return FAILURE;
}
*cmd_len = REDIS_CMD_SPPRINTF(cmd, "SENTINEL", "sS", kw, strlen(kw), name);
return SUCCESS;
}
/*
* Redis commands that don't deal with the server at all. The RedisSock*
* pointer is the only thing retrieved differently, so we just take that
* in addition to the standard INTERNAL_FUNCTION_PARAMETERS for arg parsing,
* return value handling, and thread safety. */
void redis_getoption_handler(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, redisCluster *c)
{
zend_long option;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &option)
== FAILURE)
{
RETURN_FALSE;
}
// Return the requested option
switch(option) {
case REDIS_OPT_SERIALIZER:
RETURN_LONG(redis_sock->serializer);
case REDIS_OPT_COMPRESSION:
RETURN_LONG(redis_sock->compression);
case REDIS_OPT_COMPRESSION_LEVEL:
RETURN_LONG(redis_sock->compression_level);
case REDIS_OPT_PREFIX:
if (redis_sock->prefix) {
RETURN_STRINGL(ZSTR_VAL(redis_sock->prefix), ZSTR_LEN(redis_sock->prefix));
}
RETURN_NULL();
case REDIS_OPT_READ_TIMEOUT:
RETURN_DOUBLE(redis_sock->read_timeout);
case REDIS_OPT_TCP_KEEPALIVE:
RETURN_LONG(redis_sock->tcp_keepalive);
case REDIS_OPT_SCAN:
RETURN_LONG(redis_sock->scan);
case REDIS_OPT_REPLY_LITERAL:
RETURN_LONG(redis_sock->reply_literal);
case REDIS_OPT_NULL_MBULK_AS_NULL:
RETURN_LONG(redis_sock->null_mbulk_as_null);
case REDIS_OPT_FAILOVER:
RETURN_LONG(c->failover);
case REDIS_OPT_MAX_RETRIES:
RETURN_LONG(redis_sock->max_retries);
case REDIS_OPT_BACKOFF_ALGORITHM:
RETURN_LONG(redis_sock->backoff.algorithm);
case REDIS_OPT_BACKOFF_BASE:
RETURN_LONG(redis_sock->backoff.base / 1000);
case REDIS_OPT_BACKOFF_CAP:
RETURN_LONG(redis_sock->backoff.cap / 1000);
default:
RETURN_FALSE;
}
}
void redis_setoption_handler(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, redisCluster *c)
{
zend_long val_long, option;
zval *val;
zend_string *val_str;
struct timeval read_tv;
int tcp_keepalive = 0;
php_netstream_data_t *sock;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz", &option,
&val) == FAILURE)
{
RETURN_FALSE;
}
switch(option) {
case REDIS_OPT_SERIALIZER:
val_long = zval_get_long(val);
if (val_long == REDIS_SERIALIZER_NONE
|| val_long == REDIS_SERIALIZER_PHP
|| val_long == REDIS_SERIALIZER_JSON
#ifdef HAVE_REDIS_IGBINARY
|| val_long == REDIS_SERIALIZER_IGBINARY
#endif
#ifdef HAVE_REDIS_MSGPACK
|| val_long == REDIS_SERIALIZER_MSGPACK
#endif
) {
redis_sock->serializer = val_long;
RETURN_TRUE;
}
break;
case REDIS_OPT_REPLY_LITERAL:
val_long = zval_get_long(val);
redis_sock->reply_literal = val_long != 0;
RETURN_TRUE;
case REDIS_OPT_NULL_MBULK_AS_NULL:
val_long = zval_get_long(val);
redis_sock->null_mbulk_as_null = val_long != 0;
RETURN_TRUE;
case REDIS_OPT_COMPRESSION:
val_long = zval_get_long(val);
if (val_long == REDIS_COMPRESSION_NONE
#ifdef HAVE_REDIS_LZF
|| val_long == REDIS_COMPRESSION_LZF
#endif
#ifdef HAVE_REDIS_ZSTD
|| val_long == REDIS_COMPRESSION_ZSTD
#endif
#ifdef HAVE_REDIS_LZ4
|| val_long == REDIS_COMPRESSION_LZ4
#endif
) {
redis_sock->compression = val_long;
RETURN_TRUE;
}
break;
case REDIS_OPT_COMPRESSION_LEVEL:
val_long = zval_get_long(val);
redis_sock->compression_level = val_long;
RETURN_TRUE;
case REDIS_OPT_PREFIX:
if (redis_sock->prefix) {
zend_string_release(redis_sock->prefix);
redis_sock->prefix = NULL;
}
val_str = zval_get_string(val);
if (ZSTR_LEN(val_str) > 0) {
redis_sock->prefix = val_str;
} else {
zend_string_release(val_str);
}
RETURN_TRUE;
case REDIS_OPT_READ_TIMEOUT:
redis_sock->read_timeout = zval_get_double(val);
if (redis_sock->stream) {
read_tv.tv_sec = (time_t)redis_sock->read_timeout;
read_tv.tv_usec = (int)((redis_sock->read_timeout -
read_tv.tv_sec) * 1000000);
php_stream_set_option(redis_sock->stream,
PHP_STREAM_OPTION_READ_TIMEOUT, 0,
&read_tv);
}
RETURN_TRUE;
case REDIS_OPT_TCP_KEEPALIVE:
/* Don't set TCP_KEEPALIVE if we're using a unix socket. */
if (ZSTR_VAL(redis_sock->host)[0] == '/' && redis_sock->port < 1) {
RETURN_FALSE;
}
tcp_keepalive = zval_get_long(val) > 0 ? 1 : 0;
if (redis_sock->tcp_keepalive == tcp_keepalive) {
RETURN_TRUE;
}
if (redis_sock->stream) {
/* set TCP_KEEPALIVE */
sock = (php_netstream_data_t*)redis_sock->stream->abstract;
if (setsockopt(sock->socket, SOL_SOCKET, SO_KEEPALIVE, (char*)&tcp_keepalive,
sizeof(tcp_keepalive)) == -1) {
RETURN_FALSE;
}
redis_sock->tcp_keepalive = tcp_keepalive;
}
RETURN_TRUE;
case REDIS_OPT_SCAN:
val_long = zval_get_long(val);
if (val_long == REDIS_SCAN_NORETRY) {
redis_sock->scan &= ~REDIS_SCAN_RETRY;
} else if (val_long == REDIS_SCAN_NOPREFIX) {
redis_sock->scan &= ~REDIS_SCAN_PREFIX;
} else if (val_long == REDIS_SCAN_RETRY || val_long == REDIS_SCAN_PREFIX) {
redis_sock->scan |= val_long;
} else {
break;
}
RETURN_TRUE;
case REDIS_OPT_FAILOVER:
if (c == NULL) RETURN_FALSE;
val_long = zval_get_long(val);
if (val_long == REDIS_FAILOVER_NONE ||
val_long == REDIS_FAILOVER_ERROR ||
val_long == REDIS_FAILOVER_DISTRIBUTE ||
val_long == REDIS_FAILOVER_DISTRIBUTE_SLAVES)
{
c->failover = val_long;
RETURN_TRUE;
}
break;
case REDIS_OPT_MAX_RETRIES:
val_long = zval_get_long(val);
if(val_long >= 0) {
redis_sock->max_retries = val_long;
RETURN_TRUE;
}
break;
case REDIS_OPT_BACKOFF_ALGORITHM:
val_long = zval_get_long(val);
if(val_long >= 0 &&
val_long < REDIS_BACKOFF_ALGORITHMS) {
redis_sock->backoff.algorithm = val_long;
RETURN_TRUE;
}
break;
case REDIS_OPT_BACKOFF_BASE:
val_long = zval_get_long(val);
if(val_long >= 0) {
redis_sock->backoff.base = val_long * 1000;
RETURN_TRUE;
}
break;
case REDIS_OPT_BACKOFF_CAP:
val_long = zval_get_long(val);
if(val_long >= 0) {
redis_sock->backoff.cap = val_long * 1000;
RETURN_TRUE;
}
break;
default:
php_error_docref(NULL, E_WARNING, "Unknown option '" ZEND_LONG_FMT "'", option);
break;
}
RETURN_FALSE;
}
void redis_prefix_handler(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock) {
char *key;
size_t key_len;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &key, &key_len)
==FAILURE)
{
RETURN_FALSE;
}
if (redis_sock->prefix) {
int keyfree = redis_key_prefix(redis_sock, &key, &key_len);
RETVAL_STRINGL(key, key_len);
if (keyfree) efree(key);
} else {
RETURN_STRINGL(key, key_len);
}
}
void redis_serialize_handler(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock)
{
zval *z_val;
char *val;
size_t val_len;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &z_val) == FAILURE) {
RETURN_FALSE;
}
int val_free = redis_serialize(redis_sock, z_val, &val, &val_len);
RETVAL_STRINGL(val, val_len);
if (val_free) efree(val);
}
void redis_unserialize_handler(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, zend_class_entry *ex)
{
char *value;
size_t value_len;
// Parse our arguments
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &value, &value_len)
== FAILURE)
{
RETURN_FALSE;
}
// We only need to attempt unserialization if we have a serializer running
if (redis_sock->serializer == REDIS_SERIALIZER_NONE) {
// Just return the value that was passed to us
RETURN_STRINGL(value, value_len);
}
zval z_ret;
if (!redis_unserialize(redis_sock, value, value_len, &z_ret)) {
// Badly formed input, throw an exception
zend_throw_exception(ex, "Invalid serialized data, or unserialization error", 0);
RETURN_FALSE;
}
RETURN_ZVAL(&z_ret, 0, 0);
}
void redis_compress_handler(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock) {
zend_string *zstr;
size_t len;
char *buf;
int cmp_free;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &zstr) == FAILURE) {
RETURN_FALSE;
}
cmp_free = redis_compress(redis_sock, &buf, &len, ZSTR_VAL(zstr), ZSTR_LEN(zstr));
RETVAL_STRINGL(buf, len);
if (cmp_free) efree(buf);
}
void redis_uncompress_handler(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
zend_class_entry *ex)
{
zend_string *zstr;
size_t len;
char *buf;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &zstr) == FAILURE) {
RETURN_FALSE;
} else if (ZSTR_LEN(zstr) == 0 || redis_sock->compression == REDIS_COMPRESSION_NONE) {
RETURN_STR_COPY(zstr);
}
if (!redis_uncompress(redis_sock, &buf, &len, ZSTR_VAL(zstr), ZSTR_LEN(zstr))) {
zend_throw_exception(ex, "Invalid compressed data or uncompression error", 0);
RETURN_FALSE;
}
RETVAL_STRINGL(buf, len);
efree(buf);
}
void redis_pack_handler(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock) {
int valfree;
size_t len;
char *val;
zval *zv;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zv) == FAILURE) {
RETURN_FALSE;
}
valfree = redis_pack(redis_sock, zv, &val, &len);
RETVAL_STRINGL(val, len);
if (valfree) efree(val);
}
void redis_unpack_handler(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock) {
zend_string *str;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
RETURN_FALSE;
}
if (redis_unpack(redis_sock, ZSTR_VAL(str), ZSTR_LEN(str), return_value) == 0) {
RETURN_STR_COPY(str);
}
}
/* vim: set tabstop=4 softtabstop=4 expandtab shiftwidth=4: */
redis-6.0.2/redis_commands.h 0000644 0001750 0000012 00000042473 14515245367 016572 0 ustar pyatsukhnenko wheel #ifndef REDIS_COMMANDS_H
#define REDIS_COMMANDS_H
#include "common.h"
#include "library.h"
#include "cluster_library.h"
/* Pick a random slot, any slot (for stuff like publish/subscribe) */
#define CMD_RAND_SLOT(slot) \
if(slot) *slot = rand() % REDIS_CLUSTER_MOD
/* Macro for setting the slot if we've been asked to */
#define CMD_SET_SLOT(slot,key,key_len) \
if (slot) *slot = cluster_hash_key(key,key_len);
/* Simple container so we can push subscribe context out */
typedef struct {
zend_fcall_info fci;
zend_fcall_info_cache fci_cache;
} subscribeCallback;
typedef struct subscribeContext {
char *kw;
int argc;
subscribeCallback cb;
} subscribeContext;
/* Construct a raw command */
int redis_build_raw_cmd(zval *z_args, int argc, char **cmd, int *cmd_len);
/* Construct a script command */
smart_string *redis_build_script_cmd(smart_string *cmd, int argc, zval *z_args);
/* Redis command generics. Many commands share common prototypes meaning that
* we can write one function to handle all of them. For example, there are
* many COMMAND key value commands, or COMMAND key commands. */
int redis_replicaof_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx);
int redis_empty_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_opt_str_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, char *kw,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_str_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_key_long_val_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_key_long_str_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_kv_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_key_str_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_key_key_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_key_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_key_long_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_long_long_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_key_long_long_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_key_str_str_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_key_dbl_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_key_varval_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_key_val_arr_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_key_str_arr_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_pop_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_blocking_pop_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
/* Construct SCAN and similar commands, as well as check iterator */
int redis_scan_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
REDIS_SCAN_TYPE type, char **cmd, int *cmd_len);
/* ZRANGE, ZREVRANGE, ZRANGEBYSCORE, and ZREVRANGEBYSCORE callback type */
typedef int (*zrange_cb)(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *,char**,int*,int*,short*,void**);
int redis_zrange_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_config_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_function_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_zrandmember_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_zdiff_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_zinterunion_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_zdiffstore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_zinterunionstore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_intercard_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
void **ctx);
int redis_slowlog_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_lcs_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_mpop_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, char *kw,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_restore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_pubsub_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_subscribe_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_unsubscribe_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_zrangebylex_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_gen_zlex_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_eval_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_fcall_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_failover_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_flush_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_xrange_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_georadius_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_georadiusbymember_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_geosearch_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_geosearchstore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
/* Commands which need a unique construction mechanism. This is either because
* they don't share a signature with any other command, or because there is
* specific processing we do (e.g. verifying subarguments) that make them
* unique */
int redis_info_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_script_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_acl_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_set_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_getex_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_brpoplpush_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_incr_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_decr_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_hincrby_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_hincrbyfloat_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_hmget_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_mget_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_hmset_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_hstrlen_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_bitop_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_bitcount_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_bitpos_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_pfcount_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_pfadd_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_pfmerge_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_auth_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_setbit_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_linsert_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_lrem_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_lpos_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_smove_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_hrandfield_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_hset_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_hsetnx_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_srandmember_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_select_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_zincrby_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_hdel_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_zadd_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_object_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_client_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_command_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_copy_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_fmt_scan_cmd(char **cmd, REDIS_SCAN_TYPE type, char *key, int key_len,
long it, char *pat, int pat_len, long count);
int redis_geoadd_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_geodist_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_migrate_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_xadd_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_xautoclaim_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_xclaim_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_xpending_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_xack_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_xgroup_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_xinfo_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_xread_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_xreadgroup_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_xtrim_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_lmove_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_expire_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_varkey_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_vararg_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_mset_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_sentinel_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_sentinel_str_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_sort_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
/* Commands that don't communicate with Redis at all (such as getOption,
* setOption, _prefix, _serialize, etc). These can be handled in one place
* with the method of grabbing our RedisSock* object in different ways
* depending if this is a Redis object or a RedisCluster object. */
void redis_getoption_handler(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, redisCluster *c);
void redis_setoption_handler(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, redisCluster *c);
void redis_prefix_handler(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock);
void redis_serialize_handler(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock);
void redis_unserialize_handler(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, zend_class_entry *ex);
void redis_compress_handler(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock);
void redis_uncompress_handler(INTERNAL_FUNCTION_PARAMETERS,
RedisSock *redis_sock, zend_class_entry *ex);
void redis_pack_handler(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock);
void redis_unpack_handler(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock);
#endif
/* vim: set tabstop=4 softtabstop=4 expandtab shiftwidth=4: */
redis-6.0.2/redis_session.c 0000644 0001750 0000012 00000113476 14515245367 016451 0 ustar pyatsukhnenko wheel /* -*- Mode: C; tab-width: 4 -*- */
/*
+----------------------------------------------------------------------+
| Copyright (c) 1997-2009 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Original author: Alfonso Jimenez |
| Maintainer: Nicolas Favre-Felix |
| Maintainer: Nasreddine Bouafif |
| Maintainer: Michael Grunder |
+----------------------------------------------------------------------+
*/
#include "common.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef PHP_SESSION
#include "ext/standard/info.h"
#include "php_redis.h"
#include "redis_session.h"
#include
#include "library.h"
#include "cluster_library.h"
#include "php.h"
#include "php_ini.h"
#include "php_variables.h"
#include "SAPI.h"
#include "ext/standard/url.h"
#define REDIS_SESSION_PREFIX "PHPREDIS_SESSION:"
#define CLUSTER_SESSION_PREFIX "PHPREDIS_CLUSTER_SESSION:"
/* Session lock LUA as well as its SHA1 hash */
#define LOCK_RELEASE_LUA_STR "if redis.call(\"get\",KEYS[1]) == ARGV[1] then return redis.call(\"del\",KEYS[1]) else return 0 end"
#define LOCK_RELEASE_LUA_LEN (sizeof(LOCK_RELEASE_LUA_STR) - 1)
#define LOCK_RELEASE_SHA_STR "b70c2384248f88e6b75b9f89241a180f856ad852"
#define LOCK_RELEASE_SHA_LEN (sizeof(LOCK_RELEASE_SHA_STR) - 1)
/* Check if a response is the Redis +OK status response */
#define IS_REDIS_OK(r, len) (r != NULL && len == 3 && !memcmp(r, "+OK", 3))
#define NEGATIVE_LOCK_RESPONSE 1
#define CLUSTER_DEFAULT_PREFIX() \
zend_string_init(CLUSTER_SESSION_PREFIX, sizeof(CLUSTER_SESSION_PREFIX) - 1, 0)
ps_module ps_mod_redis = {
PS_MOD_UPDATE_TIMESTAMP(redis)
};
ps_module ps_mod_redis_cluster = {
PS_MOD_UPDATE_TIMESTAMP(rediscluster)
};
typedef struct {
zend_bool is_locked;
zend_string *session_key;
zend_string *lock_key;
zend_string *lock_secret;
} redis_session_lock_status;
typedef struct redis_pool_member_ {
RedisSock *redis_sock;
int weight;
struct redis_pool_member_ *next;
} redis_pool_member;
typedef struct {
int totalWeight;
int count;
redis_pool_member *head;
redis_session_lock_status lock_status;
} redis_pool;
// static char *session_conf_string(HashTable *ht, const char *key, size_t keylen) {
// }
PHP_REDIS_API void
redis_pool_add(redis_pool *pool, RedisSock *redis_sock, int weight)
{
redis_pool_member *rpm = ecalloc(1, sizeof(redis_pool_member));
rpm->redis_sock = redis_sock;
rpm->weight = weight;
rpm->next = pool->head;
pool->head = rpm;
pool->totalWeight += weight;
}
PHP_REDIS_API void
redis_pool_free(redis_pool *pool) {
redis_pool_member *rpm, *next;
rpm = pool->head;
while (rpm) {
next = rpm->next;
redis_sock_disconnect(rpm->redis_sock, 0, 1);
redis_free_socket(rpm->redis_sock);
efree(rpm);
rpm = next;
}
/* Cleanup after our lock */
if (pool->lock_status.session_key) zend_string_release(pool->lock_status.session_key);
if (pool->lock_status.lock_secret) zend_string_release(pool->lock_status.lock_secret);
if (pool->lock_status.lock_key) zend_string_release(pool->lock_status.lock_key);
/* Cleanup pool itself */
efree(pool);
}
/* Retreive session.gc_maxlifetime from php.ini protecting against an integer overflow */
static int session_gc_maxlifetime(void) {
zend_long value = INI_INT("session.gc_maxlifetime");
if (value > INT_MAX) {
php_error_docref(NULL, E_NOTICE, "session.gc_maxlifetime overflows INT_MAX, truncating.");
return INT_MAX;
} else if (value <= 0) {
php_error_docref(NULL, E_NOTICE, "session.gc_maxlifetime is <= 0, defaulting to 1440 seconds");
return 1440;
}
return value;
}
/* Send a command to Redis. Returns byte count written to socket (-1 on failure) */
static int redis_simple_cmd(RedisSock *redis_sock, char *cmd, int cmdlen,
char **reply, int *replylen)
{
*reply = NULL;
int len_written = redis_sock_write(redis_sock, cmd, cmdlen);
if (len_written >= 0) {
*reply = redis_sock_read(redis_sock, replylen);
}
return len_written;
}
PHP_REDIS_API redis_pool_member *
redis_pool_get_sock(redis_pool *pool, const char *key) {
unsigned int pos, i;
memcpy(&pos, key, sizeof(pos));
pos %= pool->totalWeight;
redis_pool_member *rpm = pool->head;
for(i = 0; i < pool->totalWeight;) {
if (pos >= i && pos < i + rpm->weight) {
if (redis_sock_server_open(rpm->redis_sock) == 0) {
return rpm;
}
}
i += rpm->weight;
rpm = rpm->next;
}
return NULL;
}
/* Helper to set our session lock key */
static int set_session_lock_key(RedisSock *redis_sock, char *cmd, int cmd_len
)
{
char *reply;
int sent_len, reply_len;
sent_len = redis_simple_cmd(redis_sock, cmd, cmd_len, &reply, &reply_len);
if (reply) {
if (IS_REDIS_OK(reply, reply_len)) {
efree(reply);
return SUCCESS;
}
efree(reply);
}
/* Return FAILURE in case of network problems */
return sent_len >= 0 ? NEGATIVE_LOCK_RESPONSE : FAILURE;
}
static int lock_acquire(RedisSock *redis_sock, redis_session_lock_status *lock_status
)
{
char *cmd, hostname[HOST_NAME_MAX] = {0}, suffix[] = "_LOCK";
int cmd_len, lock_wait_time, retries, i, set_lock_key_result, expiry;
/* Short circuit if we are already locked or not using session locks */
if (lock_status->is_locked || !INI_INT("redis.session.locking_enabled"))
return SUCCESS;
/* How long to wait between attempts to acquire lock */
lock_wait_time = INI_INT("redis.session.lock_wait_time");
if (lock_wait_time == 0) {
lock_wait_time = 20000;
}
/* Maximum number of times to retry (-1 means infinite) */
retries = INI_INT("redis.session.lock_retries");
if (retries == 0) {
retries = 100;
}
/* How long should the lock live (in seconds) */
expiry = INI_INT("redis.session.lock_expire");
if (expiry == 0) {
expiry = INI_INT("max_execution_time");
}
/* Generate our qualified lock key */
if (lock_status->lock_key) zend_string_release(lock_status->lock_key);
lock_status->lock_key = zend_string_alloc(ZSTR_LEN(lock_status->session_key) + sizeof(suffix) - 1, 0);
memcpy(ZSTR_VAL(lock_status->lock_key), ZSTR_VAL(lock_status->session_key), ZSTR_LEN(lock_status->session_key));
memcpy(ZSTR_VAL(lock_status->lock_key) + ZSTR_LEN(lock_status->session_key), suffix, sizeof(suffix) - 1);
/* Calculate lock secret */
gethostname(hostname, HOST_NAME_MAX);
if (lock_status->lock_secret) zend_string_release(lock_status->lock_secret);
lock_status->lock_secret = strpprintf(0, "%s|%ld", hostname, (long)getpid());
if (expiry > 0) {
cmd_len = REDIS_SPPRINTF(&cmd, "SET", "SSssd", lock_status->lock_key,
lock_status->lock_secret, "NX", 2, "PX", 2,
expiry * 1000);
} else {
cmd_len = REDIS_SPPRINTF(&cmd, "SET", "SSs", lock_status->lock_key,
lock_status->lock_secret, "NX", 2);
}
/* Attempt to get our lock */
for (i = 0; retries == -1 || i <= retries; i++) {
set_lock_key_result = set_session_lock_key(redis_sock, cmd, cmd_len);
if (set_lock_key_result == SUCCESS) {
lock_status->is_locked = 1;
break;
} else if (set_lock_key_result == FAILURE) {
/* In case of network problems, break the loop and report to userland */
lock_status->is_locked = 0;
break;
}
/* Sleep unless we're done making attempts */
if (retries == -1 || i < retries) {
usleep(lock_wait_time);
}
}
/* Cleanup SET command */
efree(cmd);
/* Success if we're locked */
return lock_status->is_locked ? SUCCESS : FAILURE;
}
#define IS_LOCK_SECRET(reply, len, secret) (len == ZSTR_LEN(secret) && !strncmp(reply, ZSTR_VAL(secret), len))
static int write_allowed(RedisSock *redis_sock, redis_session_lock_status *lock_status)
{
if (!INI_INT("redis.session.locking_enabled")) {
return 1;
}
/* If locked and redis.session.lock_expire is not set => TTL=max_execution_time
Therefore it is guaranteed that the current process is still holding the lock */
if (lock_status->is_locked && INI_INT("redis.session.lock_expire") != 0) {
char *cmd, *reply = NULL;
int replylen, cmdlen;
/* Command to get our lock key value and compare secrets */
cmdlen = REDIS_SPPRINTF(&cmd, "GET", "S", lock_status->lock_key);
/* Attempt to refresh the lock */
redis_simple_cmd(redis_sock, cmd, cmdlen, &reply, &replylen);
/* Cleanup */
efree(cmd);
if (reply == NULL) {
lock_status->is_locked = 0;
} else {
lock_status->is_locked = IS_LOCK_SECRET(reply, replylen, lock_status->lock_secret);
efree(reply);
}
/* Issue a warning if we're not locked. We don't attempt to refresh the lock
* if we aren't flagged as locked, so if we're not flagged here something
* failed */
if (!lock_status->is_locked) {
php_error_docref(NULL, E_WARNING, "Session lock expired");
}
}
return lock_status->is_locked;
}
/* Release any session lock we hold and cleanup allocated lock data. This function
* first attempts to use EVALSHA and then falls back to EVAL if EVALSHA fails. This
* will cause Redis to cache the script, so subsequent calls should then succeed
* using EVALSHA. */
static void lock_release(RedisSock *redis_sock, redis_session_lock_status *lock_status)
{
char *cmd, *reply;
int i, cmdlen, replylen;
/* Keywords, command, and length fallbacks */
const char *kwd[] = {"EVALSHA", "EVAL"};
const char *lua[] = {LOCK_RELEASE_SHA_STR, LOCK_RELEASE_LUA_STR};
int len[] = {LOCK_RELEASE_SHA_LEN, LOCK_RELEASE_LUA_LEN};
/* We first want to try EVALSHA and then fall back to EVAL */
for (i = 0; lock_status->is_locked && i < sizeof(kwd)/sizeof(*kwd); i++) {
/* Construct our command */
cmdlen = REDIS_SPPRINTF(&cmd, (char*)kwd[i], "sdSS", lua[i], len[i], 1,
lock_status->lock_key, lock_status->lock_secret);
/* Send it off */
redis_simple_cmd(redis_sock, cmd, cmdlen, &reply, &replylen);
/* Release lock and cleanup reply if we got one */
if (reply != NULL) {
lock_status->is_locked = 0;
efree(reply);
}
/* Cleanup command */
efree(cmd);
}
/* Something has failed if we are still locked */
if (lock_status->is_locked) {
php_error_docref(NULL, E_WARNING, "Failed to release session lock");
}
}
#if PHP_VERSION_ID < 70300
#define REDIS_URL_STR(umem) umem
#else
#define REDIS_URL_STR(umem) ZSTR_VAL(umem)
#endif
/* {{{ PS_OPEN_FUNC
*/
PS_OPEN_FUNC(redis)
{
php_url *url;
zval params, context, *zv;
int i, j, path_len;
redis_pool *pool = ecalloc(1, sizeof(*pool));
for (i = 0, j = 0, path_len = strlen(save_path); i < path_len; i = j + 1) {
/* find beginning of url */
while ( i< path_len && (isspace(save_path[i]) || save_path[i] == ','))
i++;
/* find end of url */
j = i;
while (jquery != NULL) {
HashTable *ht;
char *query;
array_init(¶ms);
if (url->fragment) {
spprintf(&query, 0, "%s#%s", REDIS_URL_STR(url->query), REDIS_URL_STR(url->fragment));
} else {
query = estrdup(REDIS_URL_STR(url->query));
}
sapi_module.treat_data(PARSE_STRING, query, ¶ms);
ht = Z_ARRVAL(params);
REDIS_CONF_INT_STATIC(ht, "weight", &weight);
REDIS_CONF_BOOL_STATIC(ht, "persistent", &persistent);
REDIS_CONF_INT_STATIC(ht, "database", &db);
REDIS_CONF_DOUBLE_STATIC(ht, "timeout", &timeout);
REDIS_CONF_DOUBLE_STATIC(ht, "read_timeout", &read_timeout);
REDIS_CONF_LONG_STATIC(ht, "retry_interval", &retry_interval);
REDIS_CONF_STRING_STATIC(ht, "persistent_id", &persistent_id);
REDIS_CONF_STRING_STATIC(ht, "prefix", &prefix);
REDIS_CONF_AUTH_STATIC(ht, "auth", &user, &pass);
if ((zv = REDIS_HASH_STR_FIND_TYPE_STATIC(ht, "stream", IS_ARRAY)) != NULL) {
ZVAL_ZVAL(&context, zv, 1, 0);
}
zval_dtor(¶ms);
}
if ((url->path == NULL && url->host == NULL) || weight <= 0 || timeout <= 0) {
char *path = estrndup(save_path+i, j-i);
php_error_docref(NULL, E_WARNING,
"Failed to parse session.save_path (error at offset %d, url was '%s')", i, path);
efree(path);
php_url_free(url);
if (persistent_id) zend_string_release(persistent_id);
if (prefix) zend_string_release(prefix);
if (user) zend_string_release(user);
if (pass) zend_string_release(pass);
redis_pool_free(pool);
PS_SET_MOD_DATA(NULL);
return FAILURE;
}
RedisSock *redis_sock;
char *addr, *scheme;
size_t addrlen;
int port, addr_free = 0;
scheme = url->scheme ? REDIS_URL_STR(url->scheme) : "tcp";
if (url->host) {
port = url->port;
addrlen = spprintf(&addr, 0, "%s://%s", scheme, REDIS_URL_STR(url->host));
addr_free = 1;
} else { /* unix */
port = 0;
addr = REDIS_URL_STR(url->path);
addrlen = strlen(addr);
}
redis_sock = redis_sock_create(addr, addrlen, port, timeout, read_timeout,
persistent, persistent_id ? ZSTR_VAL(persistent_id) : NULL,
retry_interval);
if (db >= 0) { /* default is -1 which leaves the choice to redis. */
redis_sock->dbNumber = db;
}
if (Z_TYPE(context) == IS_ARRAY) {
redis_sock_set_stream_context(redis_sock, &context);
}
redis_pool_add(pool, redis_sock, weight);
redis_sock->prefix = prefix;
redis_sock_set_auth(redis_sock, user, pass);
if (addr_free) efree(addr);
if (persistent_id) zend_string_release(persistent_id);
if (user) zend_string_release(user);
if (pass) zend_string_release(pass);
php_url_free(url);
}
}
if (pool->head) {
PS_SET_MOD_DATA(pool);
return SUCCESS;
}
return FAILURE;
}
/* }}} */
/* {{{ PS_CLOSE_FUNC
*/
PS_CLOSE_FUNC(redis)
{
redis_pool *pool = PS_GET_MOD_DATA();
if (pool) {
if (pool->lock_status.session_key) {
redis_pool_member *rpm = redis_pool_get_sock(pool, ZSTR_VAL(pool->lock_status.session_key));
RedisSock *redis_sock = rpm ? rpm->redis_sock : NULL;
if (redis_sock) {
lock_release(redis_sock, &pool->lock_status);
}
}
redis_pool_free(pool);
PS_SET_MOD_DATA(NULL);
}
return SUCCESS;
}
/* }}} */
static zend_string *
redis_session_key(RedisSock *redis_sock, const char *key, int key_len)
{
zend_string *session;
char default_prefix[] = REDIS_SESSION_PREFIX;
char *prefix = default_prefix;
size_t prefix_len = sizeof(default_prefix)-1;
if (redis_sock->prefix) {
prefix = ZSTR_VAL(redis_sock->prefix);
prefix_len = ZSTR_LEN(redis_sock->prefix);
}
/* build session key */
session = zend_string_alloc(key_len + prefix_len, 0);
memcpy(ZSTR_VAL(session), prefix, prefix_len);
memcpy(ZSTR_VAL(session) + prefix_len, key, key_len);
return session;
}
/* {{{ PS_CREATE_SID_FUNC
*/
PS_CREATE_SID_FUNC(redis)
{
int retries = 3;
redis_pool *pool = PS_GET_MOD_DATA();
if (!pool) {
return php_session_create_id(NULL);
}
while (retries-- > 0) {
zend_string* sid = php_session_create_id((void **) &pool);
redis_pool_member *rpm = redis_pool_get_sock(pool, ZSTR_VAL(sid));
RedisSock *redis_sock = rpm ? rpm->redis_sock : NULL;
if (!redis_sock) {
php_error_docref(NULL, E_NOTICE, "Redis connection not available");
zend_string_release(sid);
return php_session_create_id(NULL);
}
if (pool->lock_status.session_key) zend_string_release(pool->lock_status.session_key);
pool->lock_status.session_key = redis_session_key(redis_sock, ZSTR_VAL(sid), ZSTR_LEN(sid));
if (lock_acquire(redis_sock, &pool->lock_status) == SUCCESS) {
return sid;
}
zend_string_release(pool->lock_status.session_key);
zend_string_release(sid);
sid = NULL;
}
php_error_docref(NULL, E_WARNING,
"Acquiring session lock failed while creating session_id");
return NULL;
}
/* }}} */
/* {{{ PS_VALIDATE_SID_FUNC
*/
PS_VALIDATE_SID_FUNC(redis)
{
char *cmd, *response;
int cmd_len, response_len;
const char *skey = ZSTR_VAL(key);
size_t skeylen = ZSTR_LEN(key);
if (!skeylen) return FAILURE;
redis_pool *pool = PS_GET_MOD_DATA();
redis_pool_member *rpm = redis_pool_get_sock(pool, skey);
RedisSock *redis_sock = rpm ? rpm->redis_sock : NULL;
if (!redis_sock) {
php_error_docref(NULL, E_WARNING, "Redis connection not available");
return FAILURE;
}
/* send EXISTS command */
zend_string *session = redis_session_key(redis_sock, skey, skeylen);
cmd_len = REDIS_SPPRINTF(&cmd, "EXISTS", "S", session);
zend_string_release(session);
if (redis_sock_write(redis_sock, cmd, cmd_len) < 0 || (response = redis_sock_read(redis_sock, &response_len)) == NULL) {
php_error_docref(NULL, E_WARNING, "Error communicating with Redis server");
efree(cmd);
return FAILURE;
}
efree(cmd);
if (response_len == 2 && response[0] == ':' && response[1] == '1') {
efree(response);
return SUCCESS;
} else {
efree(response);
return FAILURE;
}
}
/* }}} */
/* {{{ PS_UPDATE_TIMESTAMP_FUNC
*/
PS_UPDATE_TIMESTAMP_FUNC(redis)
{
char *cmd, *response;
int cmd_len, response_len;
const char *skey = ZSTR_VAL(key);
size_t skeylen = ZSTR_LEN(key);
if (!skeylen) return FAILURE;
redis_pool *pool = PS_GET_MOD_DATA();
redis_pool_member *rpm = redis_pool_get_sock(pool, skey);
RedisSock *redis_sock = rpm ? rpm->redis_sock : NULL;
if (!redis_sock) {
php_error_docref(NULL, E_WARNING, "Redis connection not available");
return FAILURE;
}
/* send EXPIRE command */
zend_string *session = redis_session_key(redis_sock, skey, skeylen);
cmd_len = REDIS_SPPRINTF(&cmd, "EXPIRE", "Sd", session, session_gc_maxlifetime());
zend_string_release(session);
if (redis_sock_write(redis_sock, cmd, cmd_len) < 0 || (response = redis_sock_read(redis_sock, &response_len)) == NULL) {
php_error_docref(NULL, E_WARNING, "Error communicating with Redis server");
efree(cmd);
return FAILURE;
}
efree(cmd);
if (response_len == 2 && response[0] == ':') {
efree(response);
return SUCCESS;
} else {
efree(response);
return FAILURE;
}
}
/* }}} */
/* {{{ PS_READ_FUNC
*/
PS_READ_FUNC(redis)
{
char *resp, *cmd;
int resp_len, cmd_len;
const char *skey = ZSTR_VAL(key);
size_t skeylen = ZSTR_LEN(key);
if (!skeylen) return FAILURE;
redis_pool *pool = PS_GET_MOD_DATA();
redis_pool_member *rpm = redis_pool_get_sock(pool, skey);
RedisSock *redis_sock = rpm ? rpm->redis_sock : NULL;
if (!redis_sock) {
php_error_docref(NULL, E_WARNING, "Redis connection not available");
return FAILURE;
}
/* send GET command */
if (pool->lock_status.session_key) zend_string_release(pool->lock_status.session_key);
pool->lock_status.session_key = redis_session_key(redis_sock, skey, skeylen);
cmd_len = REDIS_SPPRINTF(&cmd, "GET", "S", pool->lock_status.session_key);
if (lock_acquire(redis_sock, &pool->lock_status) != SUCCESS) {
php_error_docref(NULL, E_WARNING, "Failed to acquire session lock");
efree(cmd);
return FAILURE;
}
if (redis_sock_write(redis_sock, cmd, cmd_len) < 0) {
php_error_docref(NULL, E_WARNING, "Error communicating with Redis server");
efree(cmd);
return FAILURE;
}
efree(cmd);
/* Read response from Redis. If we get a NULL response from redis_sock_read
* this can indicate an error, OR a "NULL bulk" reply (empty session data)
* in which case we can reply with success. */
if ((resp = redis_sock_read(redis_sock, &resp_len)) == NULL && resp_len != -1) {
php_error_docref(NULL, E_WARNING, "Error communicating with Redis server");
return FAILURE;
}
if (resp_len < 0) {
*val = ZSTR_EMPTY_ALLOC();
} else {
*val = zend_string_init(resp, resp_len, 0);
}
efree(resp);
return SUCCESS;
}
/* }}} */
/* {{{ PS_WRITE_FUNC
*/
PS_WRITE_FUNC(redis)
{
char *cmd, *response;
int cmd_len, response_len;
const char *skey = ZSTR_VAL(key), *sval = ZSTR_VAL(val);
size_t skeylen = ZSTR_LEN(key), svallen = ZSTR_LEN(val);
if (!skeylen) return FAILURE;
redis_pool *pool = PS_GET_MOD_DATA();
redis_pool_member *rpm = redis_pool_get_sock(pool, skey);
RedisSock *redis_sock = rpm ? rpm->redis_sock : NULL;
if (!redis_sock) {
php_error_docref(NULL, E_WARNING, "Redis connection not available");
return FAILURE;
}
/* send SET command */
zend_string *session = redis_session_key(redis_sock, skey, skeylen);
cmd_len = REDIS_SPPRINTF(&cmd, "SETEX", "Sds", session, session_gc_maxlifetime(), sval, svallen);
zend_string_release(session);
if (!write_allowed(redis_sock, &pool->lock_status)) {
php_error_docref(NULL, E_WARNING, "Unable to write session: session lock not held");
efree(cmd);
return FAILURE;
}
if (redis_sock_write(redis_sock, cmd, cmd_len ) < 0 || (response = redis_sock_read(redis_sock, &response_len)) == NULL) {
php_error_docref(NULL, E_WARNING, "Error communicating with Redis server");
efree(cmd);
return FAILURE;
}
efree(cmd);
if (IS_REDIS_OK(response, response_len)) {
efree(response);
return SUCCESS;
} else {
php_error_docref(NULL, E_WARNING, "Error writing session data to Redis: %s", response);
efree(response);
return FAILURE;
}
}
/* }}} */
/* {{{ PS_DESTROY_FUNC
*/
PS_DESTROY_FUNC(redis)
{
char *cmd, *response;
int cmd_len, response_len;
const char *skey = ZSTR_VAL(key);
size_t skeylen = ZSTR_LEN(key);
redis_pool *pool = PS_GET_MOD_DATA();
redis_pool_member *rpm = redis_pool_get_sock(pool, skey);
RedisSock *redis_sock = rpm ? rpm->redis_sock : NULL;
if (!redis_sock) {
php_error_docref(NULL, E_WARNING, "Redis connection not available");
return FAILURE;
}
/* Release lock */
lock_release(redis_sock, &pool->lock_status);
/* send DEL command */
zend_string *session = redis_session_key(redis_sock, skey, skeylen);
cmd_len = REDIS_SPPRINTF(&cmd, "DEL", "S", session);
zend_string_release(session);
if (redis_sock_write(redis_sock, cmd, cmd_len) < 0 || (response = redis_sock_read(redis_sock, &response_len)) == NULL) {
php_error_docref(NULL, E_WARNING, "Error communicating with Redis server");
efree(cmd);
return FAILURE;
}
efree(cmd);
if (response_len == 2 && response[0] == ':' && (response[1] == '0' || response[1] == '1')) {
efree(response);
return SUCCESS;
} else {
efree(response);
return FAILURE;
}
}
/* }}} */
/* {{{ PS_GC_FUNC
*/
PS_GC_FUNC(redis)
{
return SUCCESS;
}
/* }}} */
/**
* Redis Cluster session handler functions
*/
/* Prefix a session key */
static char *cluster_session_key(redisCluster *c, const char *key, int keylen,
int *skeylen, short *slot) {
char *skey;
*skeylen = keylen + ZSTR_LEN(c->flags->prefix);
skey = emalloc(*skeylen);
memcpy(skey, ZSTR_VAL(c->flags->prefix), ZSTR_LEN(c->flags->prefix));
memcpy(skey + ZSTR_LEN(c->flags->prefix), key, keylen);
*slot = cluster_hash_key(skey, *skeylen);
return skey;
}
PS_OPEN_FUNC(rediscluster) {
redisCluster *c;
zval z_conf, *zv, *context;
HashTable *ht_conf, *ht_seeds;
double timeout = 0, read_timeout = 0;
int persistent = 0, failover = REDIS_FAILOVER_NONE;
zend_string *prefix = NULL, *user = NULL, *pass = NULL, *failstr = NULL;
/* Parse configuration for session handler */
array_init(&z_conf);
sapi_module.treat_data(PARSE_STRING, estrdup(save_path), &z_conf);
/* We need seeds */
zv = REDIS_HASH_STR_FIND_TYPE_STATIC(Z_ARRVAL(z_conf), "seed", IS_ARRAY);
if (zv == NULL) {
zval_dtor(&z_conf);
return FAILURE;
}
/* Grab a copy of our config hash table and keep seeds array */
ht_conf = Z_ARRVAL(z_conf);
ht_seeds = Z_ARRVAL_P(zv);
/* Optional configuration settings */
REDIS_CONF_DOUBLE_STATIC(ht_conf, "timeout", &timeout);
REDIS_CONF_DOUBLE_STATIC(ht_conf, "read_timeout", &read_timeout);
REDIS_CONF_BOOL_STATIC(ht_conf, "persistent", &persistent);
/* Sanity check on our timeouts */
if (timeout < 0 || read_timeout < 0) {
php_error_docref(NULL, E_WARNING,
"Can't set negative timeout values in session configuration");
zval_dtor(&z_conf);
return FAILURE;
}
REDIS_CONF_STRING_STATIC(ht_conf, "prefix", &prefix);
REDIS_CONF_AUTH_STATIC(ht_conf, "auth", &user, &pass);
REDIS_CONF_STRING_STATIC(ht_conf, "failover", &failstr);
/* Need to massage failover string if we have it */
if (failstr) {
if (zend_string_equals_literal_ci(failstr, "error")) {
failover = REDIS_FAILOVER_ERROR;
} else if (zend_string_equals_literal_ci(failstr, "distribute")) {
failover = REDIS_FAILOVER_DISTRIBUTE;
}
}
redisCachedCluster *cc;
zend_string **seeds, *hash = NULL;
uint32_t nseeds;
#define CLUSTER_SESSION_CLEANUP() \
if (hash) zend_string_release(hash); \
if (failstr) zend_string_release(failstr); \
if (prefix) zend_string_release(prefix); \
if (user) zend_string_release(user); \
if (pass) zend_string_release(pass); \
free_seed_array(seeds, nseeds); \
zval_dtor(&z_conf); \
/* Extract at least one valid seed or abort */
seeds = cluster_validate_args(timeout, read_timeout, ht_seeds, &nseeds, NULL);
if (seeds == NULL) {
php_error_docref(NULL, E_WARNING, "No valid seeds detected");
CLUSTER_SESSION_CLEANUP();
return FAILURE;
}
c = cluster_create(timeout, read_timeout, failover, persistent);
if (prefix) {
c->flags->prefix = zend_string_copy(prefix);
} else {
c->flags->prefix = CLUSTER_DEFAULT_PREFIX();
}
redis_sock_set_auth(c->flags, user, pass);
if ((context = REDIS_HASH_STR_FIND_TYPE_STATIC(ht_conf, "stream", IS_ARRAY)) != NULL) {
redis_sock_set_stream_context(c->flags, context);
}
/* First attempt to load from cache */
if (CLUSTER_CACHING_ENABLED()) {
hash = cluster_hash_seeds(seeds, nseeds);
if ((cc = cluster_cache_load(hash))) {
cluster_init_cache(c, cc);
goto success;
}
}
/* Initialize seed array, and attempt to map keyspace */
cluster_init_seeds(c, seeds, nseeds);
if (cluster_map_keyspace(c) != SUCCESS)
goto failure;
/* Now cache our cluster if caching is enabled */
if (hash)
cluster_cache_store(hash, c->nodes);
success:
CLUSTER_SESSION_CLEANUP();
PS_SET_MOD_DATA(c);
return SUCCESS;
failure:
CLUSTER_SESSION_CLEANUP();
cluster_free(c, 1);
return FAILURE;
}
/* {{{ PS_CREATE_SID_FUNC
*/
PS_CREATE_SID_FUNC(rediscluster)
{
redisCluster *c = PS_GET_MOD_DATA();
clusterReply *reply;
char *cmd, *skey;
zend_string *sid;
int cmdlen, skeylen;
int retries = 3;
short slot;
if (!c) {
return php_session_create_id(NULL);
}
if (INI_INT("session.use_strict_mode") == 0) {
return php_session_create_id((void **) &c);
}
while (retries-- > 0) {
sid = php_session_create_id((void **) &c);
/* Create session key if it doesn't already exist */
skey = cluster_session_key(c, ZSTR_VAL(sid), ZSTR_LEN(sid), &skeylen, &slot);
cmdlen = redis_spprintf(NULL, NULL, &cmd, "SET", "ssssd", skey,
skeylen, "", 0, "NX", 2, "EX", 2, session_gc_maxlifetime());
efree(skey);
/* Attempt to kick off our command */
c->readonly = 0;
if (cluster_send_command(c,slot,cmd,cmdlen) < 0 || c->err) {
php_error_docref(NULL, E_NOTICE, "Redis connection not available");
efree(cmd);
zend_string_release(sid);
return php_session_create_id(NULL);;
}
efree(cmd);
/* Attempt to read reply */
reply = cluster_read_resp(c, 1);
if (!reply || c->err) {
php_error_docref(NULL, E_NOTICE, "Unable to read redis response");
} else if (reply->len > 0) {
cluster_free_reply(reply, 1);
break;
} else {
php_error_docref(NULL, E_NOTICE, "Redis sid collision on %s, retrying %d time(s)", sid->val, retries);
}
if (reply) {
cluster_free_reply(reply, 1);
}
zend_string_release(sid);
sid = NULL;
}
return sid;
}
/* }}} */
/* {{{ PS_VALIDATE_SID_FUNC
*/
PS_VALIDATE_SID_FUNC(rediscluster)
{
redisCluster *c = PS_GET_MOD_DATA();
clusterReply *reply;
char *cmd, *skey;
int cmdlen, skeylen;
int res = FAILURE;
short slot;
/* Check key is valid and whether it already exists */
if (php_session_valid_key(ZSTR_VAL(key)) == FAILURE) {
php_error_docref(NULL, E_NOTICE, "Invalid session key: %s", ZSTR_VAL(key));
return FAILURE;
}
skey = cluster_session_key(c, ZSTR_VAL(key), ZSTR_LEN(key), &skeylen, &slot);
cmdlen = redis_spprintf(NULL, NULL, &cmd, "EXISTS", "s", skey, skeylen);
efree(skey);
/* We send to master, to ensure consistency */
c->readonly = 0;
if (cluster_send_command(c,slot,cmd,cmdlen) < 0 || c->err) {
php_error_docref(NULL, E_NOTICE, "Redis connection not available");
efree(cmd);
return FAILURE;
}
efree(cmd);
/* Attempt to read reply */
reply = cluster_read_resp(c, 0);
if (!reply || c->err) {
php_error_docref(NULL, E_NOTICE, "Unable to read redis response");
res = FAILURE;
} else if (reply->integer == 1) {
res = SUCCESS;
}
/* Clean up */
if (reply) {
cluster_free_reply(reply, 1);
}
return res;
}
/* }}} */
/* {{{ PS_UPDATE_TIMESTAMP_FUNC
*/
PS_UPDATE_TIMESTAMP_FUNC(rediscluster) {
redisCluster *c = PS_GET_MOD_DATA();
clusterReply *reply;
char *cmd, *skey;
int cmdlen, skeylen;
short slot;
/* No need to update the session timestamp if we've already done so */
if (INI_INT("redis.session.early_refresh")) {
return SUCCESS;
}
/* Set up command and slot info */
skey = cluster_session_key(c, ZSTR_VAL(key), ZSTR_LEN(key), &skeylen, &slot);
cmdlen = redis_spprintf(NULL, NULL, &cmd, "EXPIRE", "sd", skey,
skeylen, session_gc_maxlifetime());
efree(skey);
/* Attempt to send EXPIRE command */
c->readonly = 0;
if (cluster_send_command(c,slot,cmd,cmdlen) < 0 || c->err) {
php_error_docref(NULL, E_NOTICE, "Redis unable to update session expiry");
efree(cmd);
return FAILURE;
}
/* Clean up our command */
efree(cmd);
/* Attempt to read reply */
reply = cluster_read_resp(c, 0);
if (!reply || c->err) {
if (reply) cluster_free_reply(reply, 1);
return FAILURE;
}
/* Clean up */
cluster_free_reply(reply, 1);
return SUCCESS;
}
/* }}} */
/* {{{ PS_READ_FUNC
*/
PS_READ_FUNC(rediscluster) {
redisCluster *c = PS_GET_MOD_DATA();
clusterReply *reply;
char *cmd, *skey;
int cmdlen, skeylen, free_flag;
short slot;
/* Set up our command and slot information */
skey = cluster_session_key(c, ZSTR_VAL(key), ZSTR_LEN(key), &skeylen, &slot);
/* Update the session ttl if early refresh is enabled */
if (INI_INT("redis.session.early_refresh")) {
cmdlen = redis_spprintf(NULL, NULL, &cmd, "GETEX", "ssd", skey,
skeylen, "EX", 2, session_gc_maxlifetime());
c->readonly = 0;
} else {
cmdlen = redis_spprintf(NULL, NULL, &cmd, "GET", "s", skey, skeylen);
c->readonly = 1;
}
efree(skey);
/* Attempt to kick off our command */
if (cluster_send_command(c,slot,cmd,cmdlen) < 0 || c->err) {
efree(cmd);
return FAILURE;
}
/* Clean up command */
efree(cmd);
/* Attempt to read reply */
reply = cluster_read_resp(c, 0);
if (!reply || c->err) {
if (reply) cluster_free_reply(reply, 1);
return FAILURE;
}
/* Push reply value to caller */
if (reply->str == NULL) {
*val = ZSTR_EMPTY_ALLOC();
} else {
*val = zend_string_init(reply->str, reply->len, 0);
}
free_flag = 1;
/* Clean up */
cluster_free_reply(reply, free_flag);
/* Success! */
return SUCCESS;
}
/* {{{ PS_WRITE_FUNC
*/
PS_WRITE_FUNC(rediscluster) {
redisCluster *c = PS_GET_MOD_DATA();
clusterReply *reply;
char *cmd, *skey;
int cmdlen, skeylen;
short slot;
/* Set up command and slot info */
skey = cluster_session_key(c, ZSTR_VAL(key), ZSTR_LEN(key), &skeylen, &slot);
cmdlen = redis_spprintf(NULL, NULL, &cmd, "SETEX", "sds", skey,
skeylen, session_gc_maxlifetime(),
ZSTR_VAL(val), ZSTR_LEN(val));
efree(skey);
/* Attempt to send command */
c->readonly = 0;
if (cluster_send_command(c,slot,cmd,cmdlen) < 0 || c->err) {
efree(cmd);
return FAILURE;
}
/* Clean up our command */
efree(cmd);
/* Attempt to read reply */
reply = cluster_read_resp(c, 0);
if (!reply || c->err) {
if (reply) cluster_free_reply(reply, 1);
return FAILURE;
}
/* Clean up*/
cluster_free_reply(reply, 1);
return SUCCESS;
}
/* {{{ PS_DESTROY_FUNC(rediscluster)
*/
PS_DESTROY_FUNC(rediscluster) {
redisCluster *c = PS_GET_MOD_DATA();
clusterReply *reply;
char *cmd, *skey;
int cmdlen, skeylen;
short slot;
/* Set up command and slot info */
skey = cluster_session_key(c, ZSTR_VAL(key), ZSTR_LEN(key), &skeylen, &slot);
cmdlen = redis_spprintf(NULL, NULL, &cmd, "DEL", "s", skey, skeylen);
efree(skey);
/* Attempt to send command */
if (cluster_send_command(c,slot,cmd,cmdlen) < 0 || c->err) {
efree(cmd);
return FAILURE;
}
/* Clean up our command */
efree(cmd);
/* Attempt to read reply */
reply = cluster_read_resp(c, 0);
if (!reply || c->err) {
if (reply) cluster_free_reply(reply, 1);
return FAILURE;
}
/* Clean up our reply */
cluster_free_reply(reply, 1);
return SUCCESS;
}
/* {{{ PS_CLOSE_FUNC
*/
PS_CLOSE_FUNC(rediscluster)
{
redisCluster *c = PS_GET_MOD_DATA();
if (c) {
cluster_free(c, 1);
PS_SET_MOD_DATA(NULL);
}
return SUCCESS;
}
/* {{{ PS_GC_FUNC
*/
PS_GC_FUNC(rediscluster) {
return SUCCESS;
}
#endif
/* vim: set tabstop=4 expandtab: */
redis-6.0.2/redis_session.h 0000644 0001750 0000012 00000001155 14515245367 016444 0 ustar pyatsukhnenko wheel #ifndef REDIS_SESSION_H
#define REDIS_SESSION_H
#ifdef PHP_SESSION
#include "ext/session/php_session.h"
PS_OPEN_FUNC(redis);
PS_CLOSE_FUNC(redis);
PS_READ_FUNC(redis);
PS_WRITE_FUNC(redis);
PS_DESTROY_FUNC(redis);
PS_GC_FUNC(redis);
PS_CREATE_SID_FUNC(redis);
PS_VALIDATE_SID_FUNC(redis);
PS_UPDATE_TIMESTAMP_FUNC(redis);
PS_OPEN_FUNC(rediscluster);
PS_CLOSE_FUNC(rediscluster);
PS_READ_FUNC(rediscluster);
PS_WRITE_FUNC(rediscluster);
PS_DESTROY_FUNC(rediscluster);
PS_GC_FUNC(rediscluster);
PS_CREATE_SID_FUNC(rediscluster);
PS_VALIDATE_SID_FUNC(rediscluster);
PS_UPDATE_TIMESTAMP_FUNC(rediscluster);
#endif
#endif
redis-6.0.2/redis_sentinel.c 0000644 0001750 0000012 00000007013 14515245367 016574 0 ustar pyatsukhnenko wheel /*
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Pavlo Yatsukhnenko |
| Maintainer: Michael Grunder |
+----------------------------------------------------------------------+
*/
#include "php_redis.h"
#include "redis_commands.h"
#include "redis_sentinel.h"
#include
zend_class_entry *redis_sentinel_ce;
extern zend_class_entry *redis_exception_ce;
#if PHP_VERSION_ID < 80000
#include "redis_sentinel_legacy_arginfo.h"
#else
#include "zend_attributes.h"
#include "redis_sentinel_arginfo.h"
#endif
PHP_MINIT_FUNCTION(redis_sentinel)
{
/* RedisSentinel class */
redis_sentinel_ce = register_class_RedisSentinel();
redis_sentinel_ce->create_object = create_sentinel_object;
return SUCCESS;
}
PHP_METHOD(RedisSentinel, __construct)
{
HashTable *opts = NULL;
redis_sentinel_object *sentinel;
ZEND_PARSE_PARAMETERS_START(0, 1)
Z_PARAM_OPTIONAL
Z_PARAM_ARRAY_HT_OR_NULL(opts)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_THROWS());
sentinel = PHPREDIS_ZVAL_GET_OBJECT(redis_sentinel_object, getThis());
sentinel->sock = redis_sock_create(ZEND_STRL("127.0.0.1"), 26379, 0, 0, 0, NULL, 0);
if (opts != NULL && redis_sock_configure(sentinel->sock, opts) != SUCCESS) {
RETURN_THROWS();
}
sentinel->sock->sentinel = 1;
}
PHP_METHOD(RedisSentinel, ckquorum)
{
REDIS_PROCESS_KW_CMD("ckquorum", redis_sentinel_str_cmd, redis_boolean_response);
}
PHP_METHOD(RedisSentinel, failover)
{
REDIS_PROCESS_KW_CMD("failover", redis_sentinel_str_cmd, redis_boolean_response);
}
PHP_METHOD(RedisSentinel, flushconfig)
{
REDIS_PROCESS_KW_CMD("flushconfig", redis_sentinel_cmd, redis_boolean_response);
}
PHP_METHOD(RedisSentinel, getMasterAddrByName)
{
REDIS_PROCESS_KW_CMD("get-master-addr-by-name", redis_sentinel_str_cmd, redis_mbulk_reply_raw);
}
PHP_METHOD(RedisSentinel, master)
{
REDIS_PROCESS_KW_CMD("master", redis_sentinel_str_cmd, redis_mbulk_reply_zipped_raw);
}
PHP_METHOD(RedisSentinel, masters)
{
REDIS_PROCESS_KW_CMD("masters", redis_sentinel_cmd, sentinel_mbulk_reply_zipped_assoc);
}
PHP_METHOD(RedisSentinel, myid)
{
REDIS_PROCESS_KW_CMD("myid", redis_sentinel_cmd, redis_string_response);
}
PHP_METHOD(RedisSentinel, ping)
{
REDIS_PROCESS_KW_CMD("ping", redis_empty_cmd, redis_boolean_response);
}
PHP_METHOD(RedisSentinel, reset)
{
REDIS_PROCESS_KW_CMD("reset", redis_sentinel_str_cmd, redis_long_response);
}
PHP_METHOD(RedisSentinel, sentinels)
{
REDIS_PROCESS_KW_CMD("sentinels", redis_sentinel_str_cmd, sentinel_mbulk_reply_zipped_assoc);
}
PHP_METHOD(RedisSentinel, slaves)
{
REDIS_PROCESS_KW_CMD("slaves", redis_sentinel_str_cmd, sentinel_mbulk_reply_zipped_assoc);
}
redis-6.0.2/redis_sentinel.h 0000644 0001750 0000012 00000000362 14515245367 016601 0 ustar pyatsukhnenko wheel #ifndef REDIS_SENTINEL_H
#define REDIS_SENTINEL_H
#include "sentinel_library.h"
#define PHP_REDIS_SENTINEL_VERSION "1.0"
extern zend_class_entry *redis_sentinel_ce;
extern PHP_MINIT_FUNCTION(redis_sentinel);
#endif /* REDIS_SENTINEL_H */
redis-6.0.2/redis_sentinel.stub.php 0000644 0001750 0000012 00000002007 14515245367 020113 0 ustar pyatsukhnenko wheel sock) {
redis_sock_disconnect(obj->sock, 0, 1);
redis_free_socket(obj->sock);
}
zend_object_std_dtor(&obj->std);
}
zend_object *
create_sentinel_object(zend_class_entry *ce)
{
redis_sentinel_object *obj = ecalloc(1, sizeof(*obj) + zend_object_properties_size(ce));
zend_object_std_init(&obj->std, ce);
object_properties_init(&obj->std, ce);
memcpy(&redis_sentinel_object_handlers, zend_get_std_object_handlers(), sizeof(redis_sentinel_object_handlers));
redis_sentinel_object_handlers.offset = XtOffsetOf(redis_sentinel_object, std);
redis_sentinel_object_handlers.free_obj = free_redis_sentinel_object;
obj->std.handlers = &redis_sentinel_object_handlers;
return &obj->std;
}
PHP_REDIS_API int
sentinel_mbulk_reply_zipped_assoc(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx)
{
char inbuf[4096];
int i, nelem;
size_t len;
zval z_ret;
/* Throws exception on failure */
if (redis_sock_gets(redis_sock, inbuf, sizeof(inbuf) - 1, &len) < 0) {
RETVAL_FALSE;
return FAILURE;
}
if (*inbuf != TYPE_MULTIBULK) {
if (*inbuf == TYPE_ERR) {
redis_sock_set_err(redis_sock, inbuf + 1, len - 1);
}
RETVAL_FALSE;
return FAILURE;
}
array_init(&z_ret);
nelem = atoi(inbuf + 1);
for (i = 0; i < nelem; ++i) {
/* redis_mbulk_reply_zipped_raw calls redis_mbulk_reply_zipped
* which puts result into return_value via RETVAL_ZVAL */
redis_mbulk_reply_zipped_raw(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, ctx);
add_next_index_zval(&z_ret, return_value);
}
RETVAL_ZVAL(&z_ret, 0, 1);
return SUCCESS;
}
redis-6.0.2/sentinel_library.h 0000644 0001750 0000012 00000000577 14515245367 017147 0 ustar pyatsukhnenko wheel #ifndef REDIS_SENTINEL_LIBRARY_H
#define REDIS_SENTINEL_LIBRARY_H
#include "common.h"
#include "library.h"
typedef redis_object redis_sentinel_object;
zend_object *create_sentinel_object(zend_class_entry *ce);
PHP_REDIS_API int sentinel_mbulk_reply_zipped_assoc(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
#endif /* REDIS_SENTINEL_LIBRARY_H */