This is a complete overhaul of how aggregate connections are created and
initialized, now everything is self-contained in our usual 3 supported
client options: "aggregate", "cluster" and "replication".
The usage of callables acting as connection initializerss is now more
consistent through the various options. When the callable is invoked it
receives 3 arguments (the original set of connection parameters passed
by reference, the options container, the current option) and must return
an instance of Predis\Connection\AggregateConnectionInterface otherwise
an InvalidArgumentException is thrown.
When using "cluster" and "replication" the returned aggregate connection
is automatically populated by adding the list of nodes in $parameters,
on the other hand "aggregate" skips this automatism so it is up to the
user. In any case the user-supplied callable receives $parameters as a
reference, setting $parameters to NULL inside the body of the callable
makes the client skip automatic aggregation regardless of the option in
use.
In addition to this the actual procedure of adding nodes to an aggregate
connection has been moved directly into the respective options instead
of being spread between the client (which instead should just pass a set
of parameters and get back a fully-configured aggregate connection) and
the connection factory (and the scope of a connection factory is only to
create new connetion instances to single Redis servers).
When passing both "username" and "password" to connection parameters the
client now uses the extended AUTH command to support ACL authentication
with Redis 6.0.
The plain old authentication method is still supported like usual simply
by passing only "password" to connection parameters.
NULL or zero-length string values passed to "password" and "database" in
the connection parameters list do not trigger spurious AUTH and SELECT
commands anymore when connecting to Redis.
Fixes#436.
This is handy for accessing remote Redis instances over a secure SSL connection
which is currently a popular option or even requirement with many cloud hosting
environments.
In order to configure the client to use an SSL-encrypted connection the scheme
in the connection parameters must be either "tsl" or "rediss" and a set of SSL
options (see http://php.net/manual/en/context.ssl.php) must be provided via the
"ssl" parameter as a named array.
The following example (which does not necessarily represent an example of good
practices!) illustrates how to set the "ssl" parameter using a named array and
the equivalent URI string:
// Parameters as named array
$parameters = [
'scheme' => 'tls',
'host' => '127.0.0.1',
'ssl' => [
'cafile' => '/home/adaniele/redis.pem',
'verify_peer_name' => false,
],
];
// Parameters as URI string
$parameters = 'tls://127.0.0.1?ssl[cafile]=redis.pem&ssl[verify_peer_name]=1';
Support for SSL is currently limited to the Predis\Connection\StreamConnection
backend but we intend to investigate if it is possible to extend this feature
to Predis\Connection\PhpiredisStreamConnection in the future.
Be aware that using encrypted connections may lead to a performance degradation
especially in the connect() operation due to the overhead of the TLS handshake.
Unfortunately there is no real way to reuse SSL sessions from userland, aside
from enabling persistent connections, but this will work only on PHP >= 7.0.0
because previous versions of PHP do not provide enough info about a stream from
get_stream_meta_data().
NOTE: Redis does not have built-in support for SSL-encrypted connections, but if
you want to expose it to public networks you may want to rely on "stunnel".
These parameters augment the set of user-supplied parameters when creating a new
connection, but they do not override specific parameters when already defined.
An example of self-contained configuration using client options:
$client = new Predis\Client('tcp://127.0.0.1', [
'parameters' => [
'timeout' => 10,
],
'connections' => function ($options) {
$factory = $options->getDefault('connections');
$factory->setDefaultParameters($options->parameters);
return $factory;
},
]);
This change will be useful for both redis-cluster and redis-sentinel as it makes
it easy to apply shared parameters such as a common password for authentication
when the server returns one ore more new nodes from response (think of -MOVED).
Simply overriding one method of the standard connection factory class,
used internally by Predis, allows developers to use their own custom
connection parameters classes through the whole library.
For example, in order to support Heroku-style URIs one can do:
class HerokuParameters extends Predis\Connection\Parameters
{
protected function filter(array $parameters)
{
if (
isset($parameters['scheme']) &&
$parameters['scheme'] === 'redis'
) {
$parameters['scheme'] = 'tcp';
}
if (isset($parameters['pass'])) {
$parameters['password'] = $parameters['pass'];
}
unset($parameters['user'], $parameters['pass']);
return $parameters;
}
}
class ConnectionFactory extends Predis\Connection\Factory
{
protected function createParameters($parameters)
{
return HerokuParameters::create($parameters);
}
}
$client = new Predis\Client($_ENV['REDISCLOUD_URL'], [
'connections' => new ConnectionFactory()
]);
This idea comes in response to #196, but since we do not want to bake
support for SaaS-specific URIs in Predis this is the best compromise
we can offer leave developers free to implement their own logic for
handling these kind of URIs with the additional benefit of having it
available through the whole library (think of cluster or replication
where you have multiple nodes, thus multiple instances of connection
parameters to create).