PluginProbe
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN / 1.4.1
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN v1.4.1
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-object-cache.php +17 -33 trunk → 1.4.1 View file →
@@ -228,19 +228,10 @@
228 228 $prefix = self::effective_salt( $opts );
229 229 $timeout = self::int( $opts, 'connection_timeout', 1 );
230 230 $persist = ! empty( $opts['persistent'] );
231 231
232 - // A socket is written the way Redis Object Cache expects one,
233 - // scheme plus path, so the snippet works with that plugin too.
234 - // xSpeed's drop-in reads the same pair. (#566)
235 - $socket = Redis_Client::socket_path( $host );
236 - if ( '' !== $socket ) {
237 - $lines[] = "define( 'WP_REDIS_SCHEME', 'unix' );";
238 - $lines[] = "define( 'WP_REDIS_PATH', '" . self::esc( $socket ) . "' );";
239 - } else {
240 - $lines[] = "define( 'WP_REDIS_HOST', '" . self::esc( $host ) . "' );";
241 - $lines[] = "define( 'WP_REDIS_PORT', " . $port . ' );';
242 - }
232 + $lines[] = "define( 'WP_REDIS_HOST', '" . self::esc( $host ) . "' );";
233 + $lines[] = "define( 'WP_REDIS_PORT', " . $port . ' );';
243 234 // Emit the ACL username only when set (Redis 6+). The drop-in
244 235 // reads it; an empty user keeps the legacy default-user behavior.
245 236 if ( '' !== $user ) {
246 237 $lines[] = "define( 'WP_REDIS_USER', '" . self::esc( $user ) . "' );";
@@ -346,21 +337,13 @@
346 337 $timeout = self::int( $opts, 'connection_timeout', 1 );
347 338 $user = self::str( $opts, 'redis_user', '' );
348 339 $pass = self::str( $opts, 'redis_password', '' );
349 340 $db = self::int( $opts, 'redis_database', 0 );
350 - // A socket path has no port. phpredis opens a socket only when the
351 - // port is below 1, and the messages should name the path the user
352 - // typed rather than "path:6379". (#566)
353 - $socket = Redis_Client::socket_path( $host );
354 - $where = '' !== $socket ? $socket : "{$host}:{$port}";
355 341
356 342 if ( class_exists( '\\Redis' ) ) {
357 - $redis = new \Redis();
358 - $connected = '' !== $socket
359 - ? @$redis->connect( $socket, 0, $timeout )
360 - : @$redis->connect( $host, $port, $timeout );
361 - if ( ! $connected ) {
362 - return self::test_result( false, $backend, "Could not connect to Redis at {$where}." );
343 + $redis = new \Redis();
344 + if ( ! @$redis->connect( $host, $port, $timeout ) ) {
345 + return self::test_result( false, $backend, "Could not connect to Redis at {$host}:{$port}." );
363 346 }
364 347 // Redis 6+ ACL: when a username is set, authenticate as that user
365 348 // (phpredis ≥ 5.3 accepts ['user'=>..,'pass'=>..]); otherwise keep
366 349 // the legacy password-only form that authenticates as `default`.
@@ -373,9 +356,9 @@
373 356 }
374 357 $pong = @$redis->ping();
375 358 $ok = ( '+PONG' === $pong || true === $pong || 'PONG' === $pong );
376 359 if ( ! $ok ) {
377 - return self::test_result( false, $backend, "Redis at {$where} did not respond to PING.", $start );
360 + return self::test_result( false, $backend, "Redis at {$host}:{$port} did not respond to PING.", $start );
378 361 }
379 362 // Write-verification: PING only proves auth, not that the user can
380 363 // STORE data. ACL-namespaced hosts (xCloud) restrict a user to a
381 364 // key pattern (~redis:<id>:*); a SET outside it is NOPERM-denied and
@@ -387,17 +370,17 @@
387 370 $set = @$redis->set( $probe, '1', 5 ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- NOPERM/denied is the negative answer we report, not a fatal.
388 371 $got = @$redis->get( $probe ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- same.
389 372 @$redis->del( $probe ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- best-effort cleanup.
390 373 if ( ! $set || '1' !== (string) $got ) {
391 - return self::test_result( false, $backend, self::write_denied_message( $opts, $where ), $start );
374 + return self::test_result( false, $backend, self::write_denied_message( $opts, $host, $port ), $start );
392 375 }
393 - return self::test_result( true, $backend, self::with_prefix_advisory( "Connected to Redis at {$where} (phpredis).", $opts ), $start );
376 + return self::test_result( true, $backend, self::with_prefix_advisory( "Connected to Redis at {$host}:{$port} (phpredis).", $opts ), $start );
394 377 }
395 378
396 379 // Pure-PHP fallback — our own client, zero dependencies.
397 380 $rc = new Redis_Client( $host, $port, (float) $timeout, false );
398 381 if ( ! $rc->connect() ) {
399 - return self::test_result( false, $backend, "Could not connect to Redis at {$where}." );
382 + return self::test_result( false, $backend, "Could not connect to Redis at {$host}:{$port}." );
400 383 }
401 384 // Authenticate when a user OR a password is set. Gating on password
402 385 // alone skipped auth for the "ACL user + empty password" case, which
403 386 // then failed later at PING with a misleading message. (FBS-83118 OC-1)
@@ -411,9 +394,9 @@
411 394 $pong = $rc->ping();
412 395 $ok = ( is_string( $pong ) && false !== stripos( $pong, 'PONG' ) );
413 396 if ( ! $ok ) {
414 397 $rc->close();
415 - return self::test_result( false, $backend, "Redis at {$where} did not respond to PING.", $start );
398 + return self::test_result( false, $backend, "Redis at {$host}:{$port} did not respond to PING.", $start );
416 399 }
417 400 // Write-verification round-trip — same rationale as the phpredis path
418 401 // above. (FBS-83118 OC-2)
419 402 $probe = self::probe_key( $opts );
@@ -421,11 +404,11 @@
421 404 $got = $rc->get( $probe );
422 405 $rc->del( $probe );
423 406 $rc->close();
424 407 if ( ! $set || '1' !== (string) $got ) {
425 - return self::test_result( false, $backend, self::write_denied_message( $opts, $where ), $start );
408 + return self::test_result( false, $backend, self::write_denied_message( $opts, $host, $port ), $start );
426 409 }
427 - return self::test_result( true, $backend, self::with_prefix_advisory( "Connected to Redis at {$where} (built-in client).", $opts ), $start );
410 + return self::test_result( true, $backend, self::with_prefix_advisory( "Connected to Redis at {$host}:{$port} (built-in client).", $opts ), $start );
428 411 } catch ( \Throwable $e ) {
429 412 return self::test_result( false, $backend, 'Connection error: ' . $e->getMessage() );
430 413 }
431 414 }
@@ -653,18 +636,19 @@
653 636 * Message for a connect-OK-but-write-denied result. Points ACL/namespaced
654 637 * hosts at the fix (match the key prefix to the host's Redis Object Cache
655 638 * Key), which is exactly the xCloud failure mode. (FBS-83118 OC-2)
656 639 *
657 - * @param array $opts Settings array.
658 - * @param string $where host:port, or the socket path.
640 + * @param array $opts Settings array.
641 + * @param string $host Redis host.
642 + * @param int $port Redis port.
659 643 * @return string
660 644 */
661 - private static function write_denied_message( array $opts, string $where ): string {
645 + private static function write_denied_message( array $opts, string $host, int $port ): string {
662 646 $has_prefix = '' !== self::str( $opts, 'key_prefix', '' );
663 647 $hint = $has_prefix
664 648 ? 'The Redis user may lack write permission for this key prefix (NOPERM).'
665 649 : 'On ACL/namespaced Redis (e.g. xCloud), set Cache key prefix to the host\'s "Redis Object Cache Key" so writes land in the permitted namespace.';
666 - return "Connected to Redis at {$where}, but the cache could not store data. {$hint}";
650 + return "Connected to Redis at {$host}:{$port}, but the cache could not store data. {$hint}";
667 651 }
668 652
669 653 /**
670 654 * Full plug-and-play enable: test → write wp-config constants → install