PluginProbe
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN / 1.4.2
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN v1.4.2
1.4.2 1.4.1 1.4.0 1.3.7 1.3.6 1.3.5 1.3.4 1.3.3 1.3.2 1.3.1 1.3.0 1.2.4 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 All 36 releases
← All changes | includes/class-redis-client.php +25 -2 1.3.7 → 1.4.2 View file →
@@ -1,9 +1,9 @@
1 1 <?php
2 2 /**
3 3 * XSpeed_Redis_Client — a minimal, dependency-free Redis client.
4 4 *
5 - * Speaks the Redis wire protocol (RESP) directly over a TCP socket. It exists
5 + * Speaks the Redis wire protocol (RESP) directly over a TCP or unix socket. It exists
6 6 * so xSpeed's object cache can talk to Redis WITHOUT the phpredis extension and
7 7 * WITHOUT bundling a heavyweight library (Predis ships 700+ files for cluster /
8 8 * sentinel / pub-sub / transactions we never use). This implements exactly the
9 9 * commands the object cache needs and nothing more:
@@ -49,8 +49,30 @@
49 49 $this->persistent = $persistent;
50 50 }
51 51
52 52 /**
53 + * The unix socket path a Redis host names, or '' for a network host.
54 + *
55 + * Hosts that run Redis on a socket only (Hetzner managed servers, shared
56 + * LiteSpeed hosting) hand out a path rather than an address, written as
57 + * `/run/redis/redis.sock`, `unix:/run/redis/redis.sock` (Hetzner's own
58 + * docs) or `unix:///run/redis/redis.sock`. A socket has no port, so the
59 + * caller ignores the configured one when this returns a path. (#566)
60 + *
61 + * The drop-in carries a copy as xspeed_oc_redis_socket(), because it loads
62 + * before this class can; ObjectCacheSocketTest runs both over the same
63 + * inputs so they cannot drift.
64 + */
65 + public static function socket_path( string $host ): string {
66 + $host = trim( $host );
67 + if ( 0 === stripos( $host, 'unix:' ) ) {
68 + // unix:///path and unix:/path both name /path.
69 + $host = '/' . ltrim( substr( $host, 5 ), '/' );
70 + }
71 + return ( '' !== $host && '/' === $host[0] && '/' !== $host ) ? $host : '';
72 + }
73 +
74 + /**
53 75 * Open the socket. Returns true on success. Never throws — callers check
54 76 * the boolean and fall back to a non-persistent cache on failure.
55 77 */
56 78 public function connect(): bool {
@@ -56,11 +78,12 @@
56 78 public function connect(): bool {
57 79 $flags = STREAM_CLIENT_CONNECT | ( $this->persistent ? STREAM_CLIENT_PERSISTENT : 0 );
58 80 $errno = 0;
59 81 $errstr = '';
82 + $path = self::socket_path( $this->host );
60 83 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen, WordPress.PHP.NoSilencedErrors.Discouraged -- A raw stream socket is the only way to speak the Redis protocol; WP_Filesystem cannot open TCP sockets. Errors are captured via $errno/$errstr and surfaced as a boolean.
61 84 $sock = @stream_socket_client(
62 - "tcp://{$this->host}:{$this->port}",
85 + '' !== $path ? "unix://{$path}" : "tcp://{$this->host}:{$this->port}",
63 86 $errno,
64 87 $errstr,
65 88 $this->timeout,
66 89 $flags