手邊有一個檔案上傳功能,要從 MySQL 轉到 SQL server,原始的內容是用 PDO 的 bindValue 把二進制的檔案內容塞進資料庫:

  • $sth->bindValue(5, $fileContent, PDO::PARAM_STR);

但實際寫入會一直出現錯誤訊息:

  • SQLSTATE[IMSSP]: An error occurred translating string for input param 5 to UCS-2: No mapping for the Unicode character exists in the target multi-byte code page.

看起來就是 binary 塞不進去資料庫裡。

原本以為是因為 SQL server 是個強型別的資料庫,以前各種使用 PDO::PARAM_STR 就可以寫入的內容,現在要指定正確型別,但我把 bindValue 的型別指定成 PDO::PARAM_LOB,也還是不行。

參考了 "PHP PDO load image into MS SQL Server 2012",才發現在綁定參數時,還需要使用 bindParam 的第四個參數做編碼:

  • <?php
    $dsn = "sqlsrv:Server=localhost, 1433; Encrypt=0;Database=defaultDB";
    $dbh = new PDO($dsn, DB_ACCOUNT, DB_PASSWORD); 
    $dbh->setAttribute(PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_UTF8);
    $sth = $dbh->prepare($sql);
    (中略)

    $sth->bindParam(5, $fileContent, PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_BINARY); 
    ?>

 

這招也可以用來處理另一個詭異問題:我在 SQL server 使用 EncryptByPassPhrase() 加密,若原始字串為:

A123456789

使用 DecryptByPassPhrase() 解回來時,會發現該字串被切成 char array,每隔一個字就加料了 null (\0),變成:

A\01\02\03\04\05\06\07\08\09\0

意義上等於是:
Anull1null2null3null4null5null6null7null8null9null

在 PHP 裡,如果我先把加密字串 base64_encode() 處理,解密後再 base64_decode(),解完 Base64 還原回來的原始字串,就會自動去掉那些 null (\0)。但是在跟我對接的開發人員使用的 C# 裡,光是要 decode base64,被插入了 null (\0) 的 Base64 字串就會噴錯誤訊息。

後來的解法是連字串也都加上上述的 BINARY 編碼參數:

  • <?php
    $sth->bindParam(2, base64_encode($string), PDO::PARAM_STR, 0, PDO::SQLSRV_ENCODING_BINARY);
    ?>

以上。

arrow
arrow
    文章標籤
    sql server mssql database php
    全站熱搜
    創作者介紹
    創作者 小攻城師 的頭像
    小攻城師

    小攻城師的戰場筆記

    小攻城師 發表在 痞客邦 留言(0) 人氣()