PDO dblib многобайтовая (китайская) кодировка символов-SQL server

на машине Linux я использую PDO DBLIB для подключения к базе данных MSSQL и вставки данных в SQL_Latin1_General_CP1_CI_AS таблица. Проблема в том, что когда я пытаюсь вставить китайские символы (многобайтовые), они вставляются как 哈市香åŠåŒºç æ±Ÿè·¯å·.

мои (часть) код выглядит следующим образом:

$DBH = new PDO("dblib:host=$myServer;dbname=$myDB;", $myUser, $myPass);

$query = "
    INSERT INTO UserSignUpInfo
    (FirstName)
    VALUES
    (:firstname)";

$STH = $DBH->prepare($query);

$STH->bindParam(':firstname', $firstname);

что я пробовал до сих пор:

  1. делаешь mb_convert_encoding to UTF-16LE on $firstname и CAST как VARBINARY в запросе например:

    $firstname = mb_convert_encoding($firstname, 'UTF-16LE', 'UTF-8');

    VALUES
    (CAST(:firstname AS VARBINARY));
    

    что приводит к правильной вставке символов, пока не появятся некоторые не-многобайтовые символы, которые нарушают выполнение PDO.

  2. установка моего соединения как utf8:

    $DBH = new PDO("dblib:host=$myServer;dbname=$myDB;charset=UTF-8;", $myUser, $myPass);
    $DBH->exec('SET CHARACTER SET utf8');
    $DBH->query("SET NAMES utf8");
    
  3. задание client charset в UTF-8 в моих freetds.conf

    который не имел никакого влияния.

есть ли вообще способ вставить многобайтовые данные в этот SQL база данных? Есть ли другие обходные пути? я думал попробовать PDO ODBC или даже mssql, но подумал, что лучше спросить здесь, прежде чем тратить больше времени.

спасибо заранее.

EDIT:

Я закончил с помощью MSSQL и N префикс типа данных. Я поменяюсь и попробую PDO_ODBC, когда у меня будет больше времени. Спасибо всем за ответы!

5 ответов


есть ли вообще способ вставить многобайтовые данные в [этот конкретный] SQL база данных? Есть ли другие обходные пути?

  1. если вы можете переключиться на PDO_ODBC, Microsoft предоставляет бесплатные драйверы SQL Server ODBC для Linux (только для 64-разрядных Red Hat Enterprise Linux и 64-разрядных SUSE Linux Enterprise), которые поддерживают Unicode.

  2. если вы можете изменить на PDO_ODBC, то N-префикс для вставки Unicode будет работа.

  3. если вы можете изменить таблицы от SQL_Latin1_General_CP1_CI_AS до UTF-8 (по умолчанию для MSSQL), тогда это было бы идеально.

ваш случай более ограничен. Это решение подходит для случая, когда вы смешали многобайтовые и не-многобайтовые символы во входной строке, и вам нужно сохранить их в Латинской таблице и N префикс типа данных не работает, и вы не хотите меняться от PDO DBLIB (потому что Microsoft Unicode PDO_ODBC является едва поддерживается на linux). Вот один обходной путь.

условно закодировать входную строку как в base64. В конце концов, именно так мы можем безопасно транспортировать фотографии в соответствии с электронной почтой.

Пример:

$DBH = new PDO("dblib:host=$myServer;dbname=$myDB;", $myUser, $myPass);

$query = "
INSERT INTO [StackOverflow].[dbo].[UserSignUpInfo]
           ([FirstName])
     VALUES
           (:firstname)";

$STH = $DBH->prepare($query);

$firstname = "输入中国文字!Okay!";

/* First, check if this string has any Unicode at all */
if (strlen($firstname) != strlen(utf8_decode($firstname))) {
    /* If so, change the string to base64. */
    $firstname = base64_encode($firstname);
}

$STH->bindParam(':firstname', $firstname);
$STH->execute(); 

затем, чтобы вернуться назад, вы можете проверить строки base64 и декодировать только их без повреждения существующих записей, как Итак:

while ($row = $STH->fetch()) {
    $entry = $row[0];

    if (base64_encode(base64_decode($entry , true)) === $entry) {

         /* Decoding and re-encoding a true base64 string results in the original entry */
         print_r(base64_decode($entry) . PHP_EOL);

    } else {

         /* Previous entries not encoded will fall through gracefully */
         print_r($entry  . PHP_EOL);
    }
}

записи будут сохранены следующим образом:

Guan Tianlang
5pys6Kqe44KS5a2maGVsbG8=

но вы можете легко преобразовать их обратно в:

Guan Tianlang
输入中国文字!Okay!

сортировка здесь не имеет значения.

двухбайтовые символы должны храниться в nvarchar, nchar или ntext поля. Вам не нужно выполнять кастинг.

на n префикс типа данных означает National, и это заставляет SQL Server хранить текст как Unicode (UTF-16).

Edit:

PDO_DBLIB не поддерживает Unicode и теперь устарел.

если вы можете переключиться на PDO_ODBC, Microsoft предоставляет бесплатные драйверы SQL Server ODBC для Linux, которые поддерживают Unicode.

документация по драйверу ODBC Microsoft - SQL Server

блог-установка и использование драйвера ODBC Microsoft SQL Server для Linux


вы можете использовать совместимый с Unicode тип данных для столбца таблицы для поддержки иностранных языков (исключения показаны в правке 2).

(char, varchar, text) и (nchar, nvarchar, ntext)

Юникоде :

лучше всего подходит для US English :" одна проблема с типами данных, которые используют 1 байт для кодирования каждого символа, заключается в том, что тип данных может представлять только 256 разных символов. Это заставляет несколько спецификации кодирования (или кодовые страницы) для различных алфавитов, таких как европейские алфавиты, которые относительно малы. Также невозможно обрабатывать такие системы, как японский Кандзи или корейский алфавиты хангыль, которые имеют тысячи символов

Unicode

лучше всего подходит для систем, которые должны поддерживать хотя бы один иностранный язык: "спецификация Unicode определяет единую схему кодирования для большинства символов, широко используемых в мир. Все компьютеры последовательно переводят битовые шаблоны в данных Юникода в символы, используя единую спецификацию Юникода. Это гарантирует, что один и тот же битовый шаблон всегда преобразуется в один и тот же символ на всех компьютерах. Данные могут свободно передаваться из одной базы данных или компьютера в другую без опасения, что принимающая система неправильно переведет битовые шаблоны в символы.

пример :

также я пробовал один пример, вы можете просмотреть его ниже, это было бы полезно для вопросов, связанных с вставками иностранного языка, поскольку вопрос сейчас.Столбец, как показано ниже в nvarchar и он поддерживает китайский язык

enter image description here

изменить 1:

еще один связанный с этим вопрос обсуждается здесь

Изменить 2:

Unicode отображаются неподдерживаемые скрипты здесь


просто используйте nvarchar, ntext, nChar и когда вы хотите вставить использовать

INSERT INTO UserSignUpInfo
    (FirstName)
    VALUES
    (N'firstname');

N будет ссылаться на символ Unicode, и он является стандартным во всем мире.

Ref :

https://aalamrangi.wordpress.com/2012/05/13/storing-and-retrieving-non-english-unicode-characters-hindi-czech-arabic-etc-in-sql-server/

https://technet.microsoft.com/en-us/library/ms191200(v=sql.105).aspx

https://irfansworld.wordpress.com/2011/01/25/what-is-unicode-and-non-unicode-data-formats/


эта ссылка объясняет китайский символ в MYSQL. не удается вставить китайский символ в MySQL . Вы должны создать таблицу имя_таблицы () CHARACTER SET = utf8; Use UTF-8 при вставке в таблицу

set username utf8; INSERT INTO table_name (ABC,VAL); 

abd создать базу данных в CHARACTER SET utf8 COLLATE utf8_general_ci;

затем вы можете вставить китайский иероглиф в таблицу