当前位置: 首页> 最新文章列表> 编写自动检测和设置字符集的通用连接类:封装 mysqli::get_charset + set_charset

编写自动检测和设置字符集的通用连接类:封装 mysqli::get_charset + set_charset

M66 2025-05-18

在 PHP 开发中,字符集问题是一个常见但容易被忽视的细节。如果字符集设置不正确,可能会导致中文乱码、数据存储异常,甚至引发安全漏洞(如绕过字符集检测的 SQL 注入攻击)。
本文将介绍如何编写一个 ,它在连接数据库后自动检测当前使用的字符集,并在需要时自动切换到指定字符集,确保应用程序稳定可靠地处理多语言数据。

为什么要封装 mysqli::get_charset 和 set_charset

mysqli 扩展提供了 get_charset()set_charset() 方法:

  • get_charset() 用于获取当前连接的字符集信息;

  • set_charset() 用于设置连接使用的字符集。

然而,在实际使用中,很多开发者往往在创建连接后忘记检查或修改字符集,直接使用默认值(通常是 latin1),这为多语言支持埋下隐患。

封装这两个方法到一个通用的连接类,可以做到:
? 自动检测当前字符集
? 自动切换到所需字符集(如 utf8mb4
? 提供简洁一致的接口,减少重复代码

实现代码

以下是一个简单的 DbConnection 类实现,它封装了 mysqli 的连接逻辑,并在连接后自动调整字符集。

<?php

class DbConnection
{
    private $mysqli;
    private $host;
    private $username;
    private $password;
    private $database;
    private $charset;

    public function __construct($host, $username, $password, $database, $charset = 'utf8mb4')
    {
        $this->host     = $host;
        $this->username = $username;
        $this->password = $password;
        $this->database = $database;
        $this->charset  = $charset;

        $this->connect();
    }

    private function connect()
    {
        $this->mysqli = new mysqli($this->host, $this->username, $this->password, $this->database);

        if ($this->mysqli->connect_error) {
            die('连接失败: ' . $this->mysqli->connect_error);
        }

        // 检测当前字符集
        $currentCharsetInfo = $this->mysqli->get_charset();
        if ($currentCharsetInfo) {
            $currentCharset = $currentCharsetInfo->charset;
            if (strtolower($currentCharset) !== strtolower($this->charset)) {
                // 设置为指定字符集
                if (!$this->mysqli->set_charset($this->charset)) {
                    die('设置字符集失败: ' . $this->mysqli->error);
                }
            }
        } else {
            die('无法获取当前字符集信息: ' . $this->mysqli->error);
        }
    }

    public function getConnection()
    {
        return $this->mysqli;
    }

    public function close()
    {
        if ($this->mysqli) {
            $this->mysqli->close();
        }
    }
}

// 使用示例
$db = new DbConnection('localhost', 'db_user', 'db_pass', 'db_name');

// 执行查询
$result = $db->getConnection()->query('SELECT * FROM example_table');

if ($result) {
    while ($row = $result->fetch_assoc()) {
        print_r($row);
    }
    $result->free();
}

$db->close();

代码要点解析

1?? 构造函数接收连接信息和目标字符集
默认目标字符集为 utf8mb4,这是推荐的 MySQL 字符集,能更好地支持 Emoji 和多语言内容。

2?? 连接成功后检测当前字符集
调用 get_charset() 获取当前连接使用的字符集。

3?? 如果不同则自动切换
调用 set_charset() 改为目标字符集,避免依赖 MySQL 的默认配置。

4?? 提供关闭方法
在不需要连接时主动调用 close(),避免连接泄漏。

扩展:连接配置和错误日志

在实际项目中,你可能会希望从配置文件(如 config.php)加载数据库参数,或在出错时记录日志到文件而不是 die()。例如:

error_log('数据库错误: ' . $this->mysqli->error, 3, '/var/log/db_errors.log');

还可以结合 PDO 或其他数据库库,封装更多通用方法,如事务、预处理查询等。

示例:连接 m66.net 数据库

如果你要连接一个域名为 m66.net 的数据库,可以这样写: