mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-01 08:16:03 +00:00
Predis to v2.2.2
This commit is contained in:
@@ -3,7 +3,8 @@
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -11,25 +12,26 @@
|
||||
|
||||
namespace Predis\Connection;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Predis\Command\CommandInterface;
|
||||
use Predis\Response\Error as ErrorResponse;
|
||||
use Predis\Response\ErrorInterface as ErrorResponseInterface;
|
||||
use Predis\Response\Status as StatusResponse;
|
||||
|
||||
/**
|
||||
* Standard connection to Redis servers implemented on top of PHP's streams.
|
||||
* The connection parameters supported by this class are:.
|
||||
*
|
||||
* - scheme: it can be either 'redis', 'tcp' or 'unix'.
|
||||
* - scheme: it can be either 'redis', 'tcp', 'rediss', 'tls' or 'unix'.
|
||||
* - host: hostname or IP address of the server.
|
||||
* - port: TCP port of the server.
|
||||
* - path: path of a UNIX domain socket when scheme is 'unix'.
|
||||
* - timeout: timeout to perform the connection.
|
||||
* - timeout: timeout to perform the connection (default is 5 seconds).
|
||||
* - read_write_timeout: timeout of read / write operations.
|
||||
* - async_connect: performs the connection asynchronously.
|
||||
* - tcp_nodelay: enables or disables Nagle's algorithm for coalescing.
|
||||
* - persistent: the connection is left intact after a GC collection.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
* - ssl: context options array (see http://php.net/manual/en/context.ssl.php)
|
||||
*/
|
||||
class StreamConnection extends AbstractConnection
|
||||
{
|
||||
@@ -47,6 +49,26 @@ class StreamConnection extends AbstractConnection
|
||||
$this->disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function assertParameters(ParametersInterface $parameters)
|
||||
{
|
||||
switch ($parameters->scheme) {
|
||||
case 'tcp':
|
||||
case 'redis':
|
||||
case 'unix':
|
||||
case 'tls':
|
||||
case 'rediss':
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException("Invalid scheme: '$parameters->scheme'.");
|
||||
}
|
||||
|
||||
return $parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -60,11 +82,44 @@ class StreamConnection extends AbstractConnection
|
||||
case 'unix':
|
||||
return $this->unixStreamInitializer($this->parameters);
|
||||
|
||||
case 'tls':
|
||||
case 'rediss':
|
||||
return $this->tlsStreamInitializer($this->parameters);
|
||||
|
||||
default:
|
||||
throw new \InvalidArgumentException("Invalid scheme: '{$this->parameters->scheme}'.");
|
||||
throw new InvalidArgumentException("Invalid scheme: '{$this->parameters->scheme}'.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a connected stream socket resource.
|
||||
*
|
||||
* @param ParametersInterface $parameters Connection parameters.
|
||||
* @param string $address Address for stream_socket_client().
|
||||
* @param int $flags Flags for stream_socket_client().
|
||||
*
|
||||
* @return resource
|
||||
*/
|
||||
protected function createStreamSocket(ParametersInterface $parameters, $address, $flags)
|
||||
{
|
||||
$timeout = (isset($parameters->timeout) ? (float) $parameters->timeout : 5.0);
|
||||
$context = stream_context_create(['socket' => ['tcp_nodelay' => (bool) $parameters->tcp_nodelay]]);
|
||||
|
||||
if (!$resource = @stream_socket_client($address, $errno, $errstr, $timeout, $flags, $context)) {
|
||||
$this->onConnectionError(trim($errstr), $errno);
|
||||
}
|
||||
|
||||
if (isset($parameters->read_write_timeout)) {
|
||||
$rwtimeout = (float) $parameters->read_write_timeout;
|
||||
$rwtimeout = $rwtimeout > 0 ? $rwtimeout : -1;
|
||||
$timeoutSeconds = floor($rwtimeout);
|
||||
$timeoutUSeconds = ($rwtimeout - $timeoutSeconds) * 1000000;
|
||||
stream_set_timeout($resource, $timeoutSeconds, $timeoutUSeconds);
|
||||
}
|
||||
|
||||
return $resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a TCP stream resource.
|
||||
*
|
||||
@@ -75,42 +130,28 @@ class StreamConnection extends AbstractConnection
|
||||
protected function tcpStreamInitializer(ParametersInterface $parameters)
|
||||
{
|
||||
if (!filter_var($parameters->host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
||||
$uri = "tcp://$parameters->host:$parameters->port";
|
||||
$address = "tcp://$parameters->host:$parameters->port";
|
||||
} else {
|
||||
$uri = "tcp://[$parameters->host]:$parameters->port";
|
||||
$address = "tcp://[$parameters->host]:$parameters->port";
|
||||
}
|
||||
|
||||
$flags = STREAM_CLIENT_CONNECT;
|
||||
|
||||
if (isset($parameters->async_connect) && (bool) $parameters->async_connect) {
|
||||
if (isset($parameters->async_connect) && $parameters->async_connect) {
|
||||
$flags |= STREAM_CLIENT_ASYNC_CONNECT;
|
||||
}
|
||||
|
||||
if (isset($parameters->persistent) && (bool) $parameters->persistent) {
|
||||
$flags |= STREAM_CLIENT_PERSISTENT;
|
||||
$uri .= strpos($path = $parameters->path, '/') === 0 ? $path : "/$path";
|
||||
if (isset($parameters->persistent)) {
|
||||
if (false !== $persistent = filter_var($parameters->persistent, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)) {
|
||||
$flags |= STREAM_CLIENT_PERSISTENT;
|
||||
|
||||
if ($persistent === null) {
|
||||
$address = "{$address}/{$parameters->persistent}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$resource = @stream_socket_client($uri, $errno, $errstr, (float) $parameters->timeout, $flags);
|
||||
|
||||
if (!$resource) {
|
||||
$this->onConnectionError(trim($errstr), $errno);
|
||||
}
|
||||
|
||||
if (isset($parameters->read_write_timeout)) {
|
||||
$rwtimeout = (float) $parameters->read_write_timeout;
|
||||
$rwtimeout = $rwtimeout > 0 ? $rwtimeout : -1;
|
||||
$timeoutSeconds = floor($rwtimeout);
|
||||
$timeoutUSeconds = ($rwtimeout - $timeoutSeconds) * 1000000;
|
||||
stream_set_timeout($resource, $timeoutSeconds, $timeoutUSeconds);
|
||||
}
|
||||
|
||||
if (isset($parameters->tcp_nodelay) && function_exists('socket_import_stream')) {
|
||||
$socket = socket_import_stream($resource);
|
||||
socket_set_option($socket, SOL_TCP, TCP_NODELAY, (int) $parameters->tcp_nodelay);
|
||||
}
|
||||
|
||||
return $resource;
|
||||
return $this->createStreamSocket($parameters, $address, $flags);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,25 +167,56 @@ class StreamConnection extends AbstractConnection
|
||||
throw new InvalidArgumentException('Missing UNIX domain socket path.');
|
||||
}
|
||||
|
||||
$uri = "unix://{$parameters->path}";
|
||||
$flags = STREAM_CLIENT_CONNECT;
|
||||
|
||||
if ((bool) $parameters->persistent) {
|
||||
$flags |= STREAM_CLIENT_PERSISTENT;
|
||||
if (isset($parameters->persistent)) {
|
||||
if (false !== $persistent = filter_var($parameters->persistent, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)) {
|
||||
$flags |= STREAM_CLIENT_PERSISTENT;
|
||||
|
||||
if ($persistent === null) {
|
||||
throw new InvalidArgumentException(
|
||||
'Persistent connection IDs are not supported when using UNIX domain sockets.'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$resource = @stream_socket_client($uri, $errno, $errstr, (float) $parameters->timeout, $flags);
|
||||
return $this->createStreamSocket($parameters, "unix://{$parameters->path}", $flags);
|
||||
}
|
||||
|
||||
if (!$resource) {
|
||||
$this->onConnectionError(trim($errstr), $errno);
|
||||
/**
|
||||
* Initializes a SSL-encrypted TCP stream resource.
|
||||
*
|
||||
* @param ParametersInterface $parameters Initialization parameters for the connection.
|
||||
*
|
||||
* @return resource
|
||||
*/
|
||||
protected function tlsStreamInitializer(ParametersInterface $parameters)
|
||||
{
|
||||
$resource = $this->tcpStreamInitializer($parameters);
|
||||
$metadata = stream_get_meta_data($resource);
|
||||
|
||||
// Detect if crypto mode is already enabled for this stream (PHP >= 7.0.0).
|
||||
if (isset($metadata['crypto'])) {
|
||||
return $resource;
|
||||
}
|
||||
|
||||
if (isset($parameters->read_write_timeout)) {
|
||||
$rwtimeout = (float) $parameters->read_write_timeout;
|
||||
$rwtimeout = $rwtimeout > 0 ? $rwtimeout : -1;
|
||||
$timeoutSeconds = floor($rwtimeout);
|
||||
$timeoutUSeconds = ($rwtimeout - $timeoutSeconds) * 1000000;
|
||||
stream_set_timeout($resource, $timeoutSeconds, $timeoutUSeconds);
|
||||
if (isset($parameters->ssl) && is_array($parameters->ssl)) {
|
||||
$options = $parameters->ssl;
|
||||
} else {
|
||||
$options = [];
|
||||
}
|
||||
|
||||
if (!isset($options['crypto_type'])) {
|
||||
$options['crypto_type'] = STREAM_CRYPTO_METHOD_TLS_CLIENT;
|
||||
}
|
||||
|
||||
if (!stream_context_set_option($resource, ['ssl' => $options])) {
|
||||
$this->onConnectionError('Error while setting SSL context options');
|
||||
}
|
||||
|
||||
if (!stream_socket_enable_crypto($resource, true, $options['crypto_type'])) {
|
||||
$this->onConnectionError('Error while switching to encrypted communication');
|
||||
}
|
||||
|
||||
return $resource;
|
||||
@@ -157,7 +229,13 @@ class StreamConnection extends AbstractConnection
|
||||
{
|
||||
if (parent::connect() && $this->initCommands) {
|
||||
foreach ($this->initCommands as $command) {
|
||||
$this->executeCommand($command);
|
||||
$response = $this->executeCommand($command);
|
||||
|
||||
if ($response instanceof ErrorResponseInterface && $command->getId() === 'CLIENT') {
|
||||
// Do nothing on CLIENT SETINFO command failure
|
||||
} elseif ($response instanceof ErrorResponseInterface) {
|
||||
$this->onConnectionError("`{$command->getId()}` failed: {$response->getMessage()}", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -168,7 +246,10 @@ class StreamConnection extends AbstractConnection
|
||||
public function disconnect()
|
||||
{
|
||||
if ($this->isConnected()) {
|
||||
fclose($this->getResource());
|
||||
$resource = $this->getResource();
|
||||
if (is_resource($resource)) {
|
||||
fclose($resource);
|
||||
}
|
||||
parent::disconnect();
|
||||
}
|
||||
}
|
||||
@@ -184,7 +265,7 @@ class StreamConnection extends AbstractConnection
|
||||
$socket = $this->getResource();
|
||||
|
||||
while (($length = strlen($buffer)) > 0) {
|
||||
$written = @fwrite($socket, $buffer);
|
||||
$written = is_resource($socket) ? @fwrite($socket, $buffer) : false;
|
||||
|
||||
if ($length === $written) {
|
||||
return;
|
||||
@@ -228,7 +309,7 @@ class StreamConnection extends AbstractConnection
|
||||
$bytesLeft = ($size += 2);
|
||||
|
||||
do {
|
||||
$chunk = fread($socket, min($bytesLeft, 4096));
|
||||
$chunk = is_resource($socket) ? fread($socket, min($bytesLeft, 4096)) : false;
|
||||
|
||||
if ($chunk === false || $chunk === '') {
|
||||
$this->onConnectionError('Error while reading bytes from the server.');
|
||||
@@ -247,7 +328,7 @@ class StreamConnection extends AbstractConnection
|
||||
return;
|
||||
}
|
||||
|
||||
$multibulk = array();
|
||||
$multibulk = [];
|
||||
|
||||
for ($i = 0; $i < $count; ++$i) {
|
||||
$multibulk[$i] = $this->read();
|
||||
@@ -256,7 +337,9 @@ class StreamConnection extends AbstractConnection
|
||||
return $multibulk;
|
||||
|
||||
case ':':
|
||||
return (int) $payload;
|
||||
$integer = (int) $payload;
|
||||
|
||||
return $integer == $payload ? $integer : $payload;
|
||||
|
||||
case '-':
|
||||
return new ErrorResponse($payload);
|
||||
@@ -281,9 +364,8 @@ class StreamConnection extends AbstractConnection
|
||||
|
||||
$buffer = "*{$reqlen}\r\n\${$cmdlen}\r\n{$commandID}\r\n";
|
||||
|
||||
for ($i = 0, $reqlen--; $i < $reqlen; ++$i) {
|
||||
$argument = $arguments[$i];
|
||||
$arglen = strlen($argument);
|
||||
foreach ($arguments as $argument) {
|
||||
$arglen = strlen(strval($argument));
|
||||
$buffer .= "\${$arglen}\r\n{$argument}\r\n";
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user