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

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


先前修改成熟的一个基于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里配置了默认的连接编码,谁知道告诉我一声,我还是先把这个坑记录一下。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值