耗时5天解决thinkphp连接mysql中文乱码的问题

本文分享了一位开发者在基于ThinkPHP 3.1.2的项目中遇到的中文乱码问题及其解决过程。问题源于PHP连接MariaDB时使用的字符集不正确,最终通过调整连接设置解决了乱码现象。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

坑大,或者不大,它就在那里,等着你进。


先前修改成熟的一个基于thinkphp3.1.2的后台框架,里面有我的autoCode,本来在新项目上不想再用这么落后的版本,但考虑到后台项目不对外使用,重点是autoCode是我的进度保证,于是继续使用了这个版本。


本地开发环境是windows + phpstudy(apache,php5.4),数据库直接用线上的mariadb10.2,一切在本地就绪,可当我把这个后台项目放进线上容器(centos7 + apache + php5.4)里,满心欢喜的打开在线地址观看时,竟然发现网页中的一部分中文变成了英文问号,经过短暂的分析即刻得出:数据库里读出来的中文乱码了,而模板输出的中文是正常的。


这首先排除了页面编码的问题,而且代码在本地运行时一切正常,与线上用的是同一个数据库,因此数据库也不存在问题。

需要强调的是:

1、我给所有人要求过代码文件必须使用utf8无bom

2、每个html文件都有<meta http-equiv="content-type" content="text/html; charset=utf-8">这段

3、数据库,表及字段全是utf8,且数据库里的中文内容是正常的

4、thinkphp的config.php里面已经加入了'DB_CHARSET' => 'utf8'


我检查了许许多多的配置文件,php的和apache的,连无辜的mariadb也没有放过。显式的配置了各种与编码相关的配置项,但问题并没有解决。

深深的疑惑使我尝试过许许多多的做法,我怀疑了很多不该怀疑的东西,除了人生。

我在php入口文件里加了header("Content-type: text/html; charset=utf-8"); 

我还把thinkphp3.1.2的/Lib/Driver/Db/DbMysql.class.php中的

mysql_query("SET NAMES '".C('DB_CHARSET')."'", $this->linkID[$linkNum]);

改为了

mysql_query("SET NAMES 'utf8'", $this->linkID[$linkNum]);

然而这都是无用功。


其实非常明显,这就是php连接mariadb时的编码有问题,我一次又一次的把目光投向了apache、php和mariadb的配置文件,特别是mariadb的/etc/my.cnf.d/server.cnf,[mysqld]加入了:

character_set_server=utf8

init_connect = 'SET collation_connection = utf8_general_ci'

init_connect = 'SET NAMES utf8'

其他几个配置文件该加default-character-set = utf8的也都加了。


乱码依旧。


痛定思痛,我冷静下来,经验告诉我,也许问题就在某个被自己认为没有问题而忽视掉的地方。

于是我把以上每项又检查了一遍。


是该做点别的尝试了,于是我检查了centos7的语言环境,并安装了中文语言包。

我的期待并没有得到满足,乱码还在。


对了我刚开始还让另一个php工程师在相同环境下的另一个项目里去读同一个数据库里的中文,结果并没有乱码。

而且我直觉一定是哪个地方使得这个后台项目中php使用了latin1或者别的编码去连接mysql。

第N次的痛定思痛,我一直都很确定这就是php使用了非utf8编码去连接mysql,但我在config.php里配置了呀,甚至还在DbMysql.class.php里写死了。

于是我用php做了一个验证:

           dump(M()->query("SHOW VARIABLES LIKE '%char%'"));
           dump(M()->query("SET NAMES 'utf8'"));
           dump(M()->query("SHOW VARIABLES LIKE '%char%'"));

           die;

这段代码在我本地毫无意外的,与mysql连接的编码都是utf8,而在线上的结果正如我所想,第一行打出来的结果里,character_set_connection、character_set_client、character_set_results这三个都是latin1,而在执行第二行后,第三行打印的结果就变成utf8了。

这表明我最后的结论是正确的,可是在哪里产生的这个问题呢?


于是我再一次打开thinkphp3.1.2框架的/Lib/Driver/Db/DbMysql.class.php文件,

把其中数据库版本大于4.1的if段注释掉,改成了判断mysql_set_charset函数是否存在的if段,如下:


            $dbVersion = mysql_get_server_info($this->linkID[$linkNum]);
            /*
            if ($dbVersion >= '4.1') {
                //使用UTF8存取数据库 需要mysql 4.1.0以上支持
                mysql_query("SET NAMES '".C('DB_CHARSET')."'", $this->linkID[$linkNum]);
                mysql_query("SET character_set_client = ".C('DB_CHARSET'), $this->linkID[$linkNum]);
                mysql_query("SET character_set_results = ".C('DB_CHARSET'), $this->linkID[$linkNum]);
            }*/
            
            if (function_exists('mysql_set_charset') === false) {
                mysql_query("SET NAMES '".C('DB_CHARSET')."'", $this->linkID[$linkNum]);
            }else{
                mysql_set_charset(C('DB_CHARSET'), $this->linkID[$linkNum]);

            }


问题到此解决。

我先是震惊,问题居然这么简单,就是$dbVersion >= '4.1'这个判断没进去,于是我想起了我用的是mariadb10.2,确实按照字符串来对比版本的话,这盘算我输。

线上把$dbVersion这个变量打出来看了下,确实是 string(19) "10.2.12-MariaDB-log"

我又疑惑了,那我本地也是用的这同一个库啊,难道?

我在本地也打印了下$dbVersion,结果竟然是 string(25) "5.5.5-10.2.12-MariaDB-log"

这个疑问先留着,还有就是前面我明明在mariadb的server.cnf里配置了默认的连接编码,谁知道告诉我一声,我还是先把这个坑记录一下。


### 数据转换的概念与方法 数据转换是指将一种形式的数据转化为另一种形式的过程,通常用于满足特定的应用需求或优化程序性能。以下是常见的数据转换方法及其具体实现: #### 1. **C#中的数据类型转换** 在C#中,数据类型的转换可以通过多种方式进行,包括但不限于隐式转换、显式转换、`Convert`类、字符串解析以及`ToString()`方法[^1]。 - **隐式转换** 隐式转换发生在无需额外操作即可完成的类型之间,例如从较小范围的数值类型到较大范围的数值类型(如 `int` 转换为 `long`)。这种转换不会丢失精度也不会引发异常。 - **显式转换** 显式转换需要开发者手动指定,可能涉及数据损失或抛出异常的情况。例如 `(double)myIntValue;` - **使用 Convert 类** C# 提供了一个名为 `Convert` 的静态类,可以方便地执行各种类型之间的转换。例如: ```csharp int intValue = Convert.ToInt32("123"); ``` - **字符串解析** 解析是一种通过字符串表示的形式将其转换为目标类型的常见方式。例如: ```csharp string str = "456"; int result = int.Parse(str); ``` - **ToString 方法** 将任意对象转换为其字符串表示形式的一种通用方法。几乎所有 .NET 对象都支持此功能。例如: ```csharp double d = 123.45; string s = d.ToString(); ``` --- #### 2. **文本文件转二维数组 (Array)** 对于处理结构化数据的任务,比如读取 `.txt` 文件并将其内容存储为二维数组,可以采用如下方法[^3]: 假设有一个简单的 CSV 格式的文本文件,每行代表一组记录,字段间由逗号分隔,则可通过以下代码实现其加载至二维数组的操作: ```csharp string filePath = @"example.txt"; // 假设这是路径名 List<string[]> lines = new List<string[]>(); using (StreamReader reader = new StreamReader(filePath)) { while (!reader.EndOfStream) { var line = reader.ReadLine(); // 按行读取 var values = line.Split(','); // 使用逗号作为分隔符拆分行 lines.Add(values); // 添加分割后的结果到列表 } } // 将 List 转换成 Array var arrayResult = lines.ToArray(); ``` 上述代码片段展示了如何逐行读入文件,并利用 `Split` 函数按自定义分隔符分解每一行的内容,最终形成一个二维字符串数组。 --- #### 3. **图像数据增强技术应用于数据集准备阶段** 除了传统的数值型数据外,在机器学习领域特别是计算机视觉方向上,还存在针对图像数据的预处理手段——即所谓的 *数据增强* 技术[^2]。这些技术不仅有助于扩充训练样本数量,还能有效缓解因数据不足而导致的过拟合现象。 一些典型的数据增强策略包括但不限于裁剪(Crop),随机水平翻转(Random Horizontal Flip),颜色抖动(Color Jittering),旋转(Rotation)等变换操作。下面给出一段 Python 中基于 PyTorch 库实现简单图像增广的例子: ```python import torchvision.transforms as transforms transform_pipeline = transforms.Compose([ transforms.RandomResizedCrop(224), transforms.RandomHorizontalFlip(), transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1), transforms.ToTensor() ]) ``` 这里构建了一条流水线,依次应用不同的几何和色彩空间上的调整动作给输入图片施加影响,从而生成多样化的版本参与后续的学习过程。 --- ### 总结 无论是基础编程语言层面还是高级人工智能框架内部,数据转换都是不可或缺的一环。它贯穿整个开发周期的不同环节,从原始素材获取直至最后成果展示均有所体现。掌握好各类工具和技术能够显著提升工作效率及产品质量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值