ThinkPHP 3.1.x 连接多个数据库使用不同字符编码的方法

时间:2021-12-19 17:26:29

因工作需要,某个项目需要用到ThinkPHP3.1.3进行开发。

因为项目有历史原因,需要连接两个字符编码不同的数据库,一个是UTF8,另一个LATIN1。

用过ThinkPHP的都知道,在/conf/config.php中,找到DB_CHARSET就能设置连接数据库的字符编码。

ThinkPHP默认的字符编码为utf8,可以根据需要修改为LATIN1,GBK,等字符编码。

'DB_CHARSET' => 'utf8'

因为这个项目用到两个数据库,主数据库的charset是utf8,在config.php中配置

//數據庫
'DB_HOST'=>'localhost',
'DB_NAME'=>'main',
'DB_USER'=>'main',
'DB_PWD'=>'mainpassword',

另一个数据库我在config.php中是使用下面的方式配置和调用的。

//数据库配置2
'OTHERDB_CONFIG' => array(
	'db_type'  => 'mysql',
	'db_user'  => 'other',
	'db_pwd'   => 'otherpassword',
	'db_host'  => '192.168.1.1',
	'db_port'  => '3306',
	'db_name'  => 'other',
 ),

调用方式

$member = M('member', null, 'OTHERDB_CONFIG');
$data = $this->db(1, "OTHERDB_CONFIG")->query("select * from member order by addtime desc");

由于main DB需要使用utf8编码,other DB需要使用LATIN1编码,只有一个DB_CHARSET参数不能满足。

然而我把OTHERDB_CONFIG修改加入db_charset也是无效。

//数据库配置2
'OTHERDB_CONFIG' => array(
	'db_type'  => 'mysql',
	'db_user'  => 'other',
	'db_pwd'   => 'otherpassword',
	'db_host'  => '192.168.1.1',
	'db_port'  => '3306',
	'db_name'  => 'other',
	'db_charset' => 'LATIN1' // 加入无效
 ),

难道ThinkPHP不支持连接多个数据库使用不同的字符编码吗?


查看ThinkPHP源码,找到关于数据库的部分

ThinkPHP/Lib/Driver/Db/DbMysql.class.php

function connect中找到一句,

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

原来ThinkPHP是这样设置连接数据库的字符编码的,居然是直接读取C('DB_CHARSET')的值作为连接数据库的字符编码,并没有提供其他参数设置。


connect 方法是可以传入$config参数的,既然如此,就可以把charset通过$config参数传入,然后修改DbMysql.class.php使其支持根据$config参数设置连接数据库的字符编码了。

因为DbMysql.class.php 是由Db.class.php 调用的,因此$config参数是在Db.class.php中传入。

打开ThinkPHP/Lib/Core/Db.class.php,找到function parseConfig

$config参数的格式如下:

$db_config = array(
  'dbms'      =>  $db_config['db_type'],
  'username'  =>  $db_config['db_user'],
  'password'  =>  $db_config['db_pwd'],
  'hostname'  =>  $db_config['db_host'],
  'hostport'  =>  $db_config['db_port'],
  'database'  =>  $db_config['db_name'],
  'dsn'       =>  $db_config['db_dsn'],
  'params'    =>  $db_config['db_params'],
);

因此,我们可以在config.php配置中加入db_params参数,设置db_charset了。


DbMysql.class.php 修改如下, 加入判断$config['params]['db_charset']是否存在,如存在使用参数设置的db_charset否则使用C('DB_CHARSET')

/**
 * 连接数据库方法
 * @access public
 * @throws ThinkExecption
 */
public function connect($config='',$linkNum=0,$force=false) {
    if ( !isset($this->linkID[$linkNum]) ) {
        if(empty($config))  $config =   $this->config;
        // 处理不带端口号的socket连接情况
        $host = $config['hostname'].($config['hostport']?":{$config['hostport']}":'');
        // 是否长连接
        $pconnect   = !empty($config['params']['persist'])? $config['params']['persist']:$this->pconnect;
        if($pconnect) {
            $this->linkID[$linkNum] = mysql_pconnect( $host, $config['username'], $config['password'],131072);
        }else{
            $this->linkID[$linkNum] = mysql_connect( $host, $config['username'], $config['password'],true,131072);
        }
        if ( !$this->linkID[$linkNum] || (!empty($config['database']) && !mysql_select_db($config['database'], $this->linkID[$linkNum])) ) {
            throw_exception(mysql_error());
        }
        $dbVersion = mysql_get_server_info($this->linkID[$linkNum]);

        if(isset($config['params']['db_charset'])){
            //使用指定編碼存取数据库
            mysql_query("SET NAMES '".$config['params']['db_charset']."'", $this->linkID[$linkNum]);
        }else{
            //使用UTF8存取数据库
            mysql_query("SET NAMES '".C('DB_CHARSET')."'", $this->linkID[$linkNum]);
        }

        //设置 sql_model
        if($dbVersion >'5.0.1'){
            mysql_query("SET sql_mode=''",$this->linkID[$linkNum]);
        }
        // 标记连接成功
        $this->connected    =   true;
        // 注销数据库连接配置信息
        if(1 != C('DB_DEPLOY_TYPE')) unset($this->config);
    }
    return $this->linkID[$linkNum];
}

OTHERDB_CONFIG修改如下:

//数据库配置2
'OTHERDB_CONFIG' => array(
	'db_type'  => 'mysql',
	'db_user'  => 'other',
	'db_pwd'   => 'otherpassword',
	'db_host'  => '192.168.1.1',
	'db_port'  => '3306',
	'db_name'  => 'other',
	'db_params' => array('db_charset' => 'LATIN1')
 ),

 以后就可以通过db_params设置db_charset了。