2010/04/15

CodeIgniter 連接 MS SQL 2008 並解決UTF-8問題

CI對MS SQL的支援度不是很好
連接時使用預設的$db['default']['dbdriver'] = "mssql" 根本連不到
找到第一個解決方法是使用odbc去連接MS SQL
原文:http://codeigniter.com/forums/viewthread/70448/
DB參數要設成

$db['default']['hostname'] = "Driver={SQL Server Native Client 10.0};Server=hostname;Database=db_name;";
$db['default']['username'] = "username";
$db['default']['password'] = "passwd";
$db['default']['database'] = "db_name";
$db['default']['dbdriver'] = "odbc";
$db['default']['dbprefix'] = "";
$db['default']['pconnect'] = TRUE;
$db['default']['db_debug'] = TRUE;
$db['default']['cache_on'] = FALSE;
$db['default']['cachedir'] = "";
$db['default']['char_set'] = "utf8";
$db['default']['dbcollat'] = "utf8_general_ci";

但是CI內的Active Record全部失效,只能用$this->db->query( sql cmd ) 連接
這問題倒還好,問題大的是他不支援UTF-8內的特殊字(如:烱、堃)
所以繼續找....

第二個解決方法是使用MS為PHP出的Microsoft SQL Server Driver for PHP
有好人幫忙寫了CI 1.7.2的DB Driver
網址:http://www.phrenzy.org/code/sql-server-and-php/
作法如下:

  1. 把下載回來的sqlsrv-1.1.tar.gz內的三個檔案 (sqlsrv_*.php) 解壓縮到system\database\drivers\sqlsrv內

  2. DB參數改回原來的樣子,$db['default']['dbdriver'] = "sqlsrv"

  3. 安裝Microsoft SQL Server Driver for PHP,這個步驟好多,要裝程式,然後放至DLL檔到PHP\EXT內,再修改PHP.INI

理論上就可以連接了,也可以使用 $this->db->get() 來抓資料

不過作者說目前有三個問題,我自大的把它翻成中文

  1. 可能不支援MS SQL DRIVER 10的版本,請考慮清楚再升級

  2. num_rows功能可能有問題,作者已經修正但可能影響效能

  3. UTF8不支援,除非是使用參數代入QUERY,但是CI不支援這樣的方式(下述)


但是由於MS SQL Driver如要使用UTF8的資料,需要使用傳參數的方式
很可惜的,即使使用 $this->db->query( 'sql cmd', $param ) 封裝查詢(Query Bindings) 還是無法正常將特殊字插入SQL內
又翻了好幾個頁面跟CI CODE,推測CI只是把 SQL CMD內的 ? 取代成 數值
跟直接將數值寫進SQL CMD是一樣的,所以有跟沒有一樣

最容易明白使否使用參數QUERY,就是用 $this->db->last_query() 查看結果
CI 用 $this->db->query( 'sql cmd', $param ) 會顯示
INSERT INTO temp ( NO, NAME, ID ) VALUES( 1 , 'aaa' , 'ABC' );
如果是參數QUERY,會顯示
INSERT INTO temp ( NO, NAME, ID ) VALUES( ? , ? , ? );

我就做了很大膽的實驗,修改Framework的檔案= ="
database/driver/sqlsrv/sqlsrv_driver,php
原本為
  
function _execute($sql){        
 $sql = $this->_prep_query($sql);        
 return sqlsrv_query($this->conn_id, $sql, NULL, array(            
  'Scrollable'                => SQLSRV_CURSOR_STATIC,            
  'SendStreamParamsAtExec'    => true        
 ));    
}

修改後

function _execute($sql,$data=NULL){        
 $sql = $this->_prep_query($sql);        
 return sqlsrv_query($this->conn_id, $sql, $data, array(            
  'Scrollable'                => SQLSRV_CURSOR_STATIC,            
  'SendStreamParamsAtExec'    => true        
 ));    
}

database/DB_driver.php
原本為

function query($sql, $binds = FALSE, $return_object = TRUE)
{
        .....        
        // Compile binds if needed        
        if ($binds !== FALSE)        
        {            
         $sql = $this->compile_binds($sql, $binds);                    
        }       
        .....       
        // Run the Query        
        if (FALSE === ($this->result_id = $this->simple_query($sql)))
        {             
         ....    
        }          
         ...   
}

function simple_query($sql)    
{        
 if ( ! $this->conn_id)        
 {           
  $this->initialize();        
 }
    return $this->_execute($sql);    
}

修改為
function query($sql, $binds = FALSE, $return_object = TRUE)    {
  .....
    // Compile binds if needed
    if ($binds !== FALSE)
    {
        if( !is_array($binds) ) $binds = array($binds);                   
    }else{            
     $binds = NULL;        
    }
  .....
 // Run the Query
    if (FALSE === ($this->result_id = $this->simple_query($sql,$binds)))
    {
        ....
 }       
  ...   
}

function simple_query($sql,$data=NULL)    
{        
 if ( ! $this->conn_id)        
 {            
  $this->initialize();        
 }
    return $this->_execute($sql,$data);    
}


簡單來說就是把它修改成可以使用傳參數的方法新增資料
目前只試過INSERT可以用,穩定性不保證!

1 則留言:

  1. 你好,

    正在學習CI,也想連MSSQL資料庫.
    感謝你這篇的說明,讓我了解許多.

    另外想問一下,是否可寄給我 sqlsrv-1.1.tar.gz 檔案,因為原來網址一直連不上,感謝幫忙.

    版主回覆:(06/17/2010 04:01:06 PM)


    原來的壓縮檔不知道去哪了,這是我目前使用的
    SkyDrive
    http://cid-6693c2b1bee63a1b.office.live.com/self.aspx/.Public/sqlsrv.rar

    回覆刪除