一个系统性全面的 PHP/Redis/Session Save 的检测单一PHP文件

<?php
// 开启错误报告,便于调试
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

// 检查 PHP 版本和 Redis 扩展
echo "<h1>PHP/Redis/Session 保存功能检测</h1>";
echo "<p><strong>步骤 1: 检查基本环境</strong></p>";
echo "PHP 版本: " . PHP_VERSION . "<br>";
if (extension_loaded('redis')) {
    echo "php-redis 扩展版本: " . phpversion('redis') . "<br>";
} else {
    die("错误: php-redis 扩展未加载。请检查 php.ini 是否包含 extension=redis.so。<br>");
}
if (extension_loaded('igbinary')) {
    echo "php-igbinary 扩展版本: " . phpversion('igbinary') . "<br>";
} else {
    echo "警告: php-igbinary 扩展未加载,但你的配置使用 igbinary 序列化器。建议安装。<br>";
}

// 检查 Redis 连接
echo "<p><strong>步骤 2: 测试 Redis 连接</strong></p>";
try {
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);  // 根据你的 session.save_path 配置
    if ($redis->ping()) {
        echo "Redis 连接成功 (PING 返回 PONG)。<br>";
    } else {
        echo "Redis 连接失败。<br>";
    }
} catch (Exception $e) {
    echo "Redis 连接错误: " . $e->getMessage() . "<br>";
    echo "建议: 检查 Redis 服务是否运行 (sudo systemctl status redis-server),端口是否为 6379,bind 是否包含 127.0.0.1。<br>";
    if (strpos($e->getMessage(), 'auth') !== false) {
        echo "可能需要密码: 更新 session.save_path 为 'tcp://127.0.0.1:6379?auth=your_password'。<br>";
    }
    die();  // 如果连接失败,停止后续测试
}

// 检查 session 配置
echo "<p><strong>步骤 3: 检查 session 配置</strong></p>";
echo "session.save_handler: " . ini_get('session.save_handler') . "<br>";
echo "session.save_path: " . ini_get('session.save_path') . "<br>";
echo "session.serialize_handler: " . ini_get('session.serialize_handler') . "<br>";
echo "session.gc_maxlifetime: " . ini_get('session.gc_maxlifetime') . " 秒<br>";
if (ini_get('session.save_handler') !== 'redis') {
    echo "警告: session.save_handler 不是 'redis'。请在 php.ini 中设置。<br>";
}
if (ini_get('session.serialize_handler') !== 'igbinary') {
    echo "警告: session.serialize_handler 不是 'igbinary'。你的配置指定了 igbinary,但实际未匹配。<br>";
}

// 测试 session 写入和读取
echo "<p><strong>步骤 4: 测试 session 写入和读取</strong></p>";
session_start();  // 启动 session
$session_id = session_id();
echo "当前 Session ID: " . $session_id . "<br>";

// 写入测试数据
if (!isset($_SESSION['test_key'])) {
    $_SESSION['test_key'] = 'This is a test value from ' . date('Y-m-d H. i:s');
    echo "已写入 session 数据: " . $_SESSION['test_key'] . "<br>";
} else {
    echo "从 session 读取数据: " . $_SESSION['test_key'] . "<br>";
}

// 强制写入 session
session_write_close();
echo "Session 已写入 Redis。<br>";

// 检查 Redis 中的 session 数据
echo "<p><strong>步骤 5: 检查 Redis 中的 session 数据</strong></p>";
$redis_key = 'PHPREDIS_SESSION:' . $session_id;
if ($redis->exists($redis_key)) {
    $session_data = $redis->get($redis_key);
    echo "Redis 键存在: " . $redis_key . "<br>";
    echo "Redis 中的 session 数据 (原始): " . bin2hex($session_data) . " (igbinary 序列化数据)<br>";  // 以十六进制显示,因为 igbinary 是二进制
    echo "TTL (过期时间): " . $redis->ttl($redis_key) . " 秒 (应接近 gc_maxlifetime)<br>";
} else {
    echo "错误: Redis 中未找到 session 键 " . $redis_key . "。<br>";
    echo "可能原因: <ul>
        <li>session.save_path 配置错误(检查端口、IP 或 ?database=0)。</li>
        <li>Redis 权限问题(检查 /var/lib/redis 目录权限,chown redis:redis)。</li>
        <li>igbinary 序列化失败(尝试切换到 php_serialize 测试)。</li>
        <li>Redis 内存满或 maxmemory-policy 导致键被删除(检查 redis-cli INFO memory)。</li>
        <li>session 未正确启动(检查 PHP 错误日志 /var/log/php8.1-fpm.log)。</li>
    </ul>";
}

// 测试读取并验证
session_start();  // 重新启动 session 以读取
if (isset($_SESSION['test_key'])) {
    echo "Session 数据读取成功: " . $_SESSION['test_key'] . "<br>";
} else {
    echo "错误: Session 数据读取失败。<br>";
}
session_write_close();

// 额外诊断: 列出所有 session 键
echo "<p><strong>步骤 6: 列出 Redis 中所有 PHPREDIS_SESSION 键</strong></p>";
$all_keys = $redis->keys('PHPREDIS_SESSION:*');
if (!empty($all_keys)) {
    echo "找到的 session 键:<ul>";
    foreach ($all_keys as $key) {
        echo "<li>" . $key . " (TTL: " . $redis->ttl($key) . " 秒)</li>";
    }
    echo "</ul>";
} else {
    echo "Redis 中没有 PHPREDIS_SESSION 键。<br>";
}

// 清理测试数据(可选,手动注释掉以保留)
if (isset($_GET['clean'])) {
    $redis->del($redis_key);
    echo "已清理测试 session 键。<br>";
}

// 结束 Redis 连接
$redis->close();

echo "<p><strong>检测完成</strong></p>";
echo "如果问题未解决,请检查服务器日志,并提供输出结果给我进一步分析。<br>";
echo "提示: 访问 ?clean=1 以清理测试数据。<br>";
?>

你可以将此文件命名为 redis_session_debug.php,上传到你的服务器上,通过浏览器访问它(例如 http://yourdomain/redis_session_debug.php)。它会输出诊断结果。如果有问题,会显示错误信息。

为了全面性,我在代码中添加了异常处理和详细输出。确保你的环境已启用 display_errors = On 或检查服务器日志。

发表评论

人生梦想 - 关注前沿的计算机技术 acejoy.com 🐾 步子哥の博客 🐾 背多分论坛 🐾 知差(chai)网 🐾 DeepracticeX 社区 🐾 老薛主机 🐾