Как хранить и извлекать расширенные символы ASCII в MSSQL

Я был удивлен, что не смог найти прямой ответ на этот вопрос путем поиска.

у меня есть веб-приложение на PHP, которое принимает пользовательский ввод. Из-за характера приложения пользователи могут часто использовать расширенные символы ASCII (a.к. a. "ALT codes").

моя конкретная проблема на данный момент с кодом ALT 26, который является стрелкой вправо (→). Это будет сопровождаться другим текстом, который будет храниться в том же поле (например, 'this→that').

мой тип столбца-NVARCHAR.

вот что я пробовал:

  1. Я пробовал не делать никаких преобразований и просто вставлять значение как обычно, но значение сохраняется как thisâ??that.

  2. Я попытался преобразовать значение в UCS-2 в PHP, используя iconv('UTF-8', 'UCS-2', $value), но я получаю сообщение об ошибке, говорящее Unclosed quotation mark after the character string 't'.. Запрос заканчивается следующим образом:UPDATE myTable SET myColumn = 'this�!that'.

  3. Я пробовал сделать приведенное выше преобразование и затем добавление N перед указанным значением, но я получаю то же сообщение об ошибке. Запрос выглядит следующим образом:UPDATE myTable SET myColumn = N'this�!that'.

  4. Я попытался удалить преобразование UCS-2 и просто добавить N перед указанным значением, и запрос снова работает, но значение сохраняется как thisâ that.

  5. Я пробовал использовать utf8_decode($value) в PHP, но тогда стрелка просто заменяется вопросительным знаком.

так может кто-нибудь ответить (казалось бы, простой) вопрос о том, как я могу сохранить это значение в своей базе данных, а затем получить его, как он был первоначально набран?

я использую PHP 5.5 и MSSQL 2012. Если какой-либо вопрос о версии драйвера/ОС вступает в игру, это сервер Linux, подключающийся через FreeTDS. Изменить это невозможно.

4 ответов


вы можете попробовать base64 кодирование ввода, это довольно тривиально обрабатывать с помощью PHP base64_encode() и base64_decode() и он должен обрабатывать то, что ваши пользователи бросают на него.

(edit: вы, по-видимому, также можете сделать кодировка base64 на стороне SQL Server. Это не похоже на то, что он должен нести ответственность за ИМХО, но это вариант.)


вроде freetds.conf - это неправильно. Вам нужна версия протокола TDS >= 7.0 для поддержки unicode. Посмотреть подробнее.

редактировать freetds.conf:

[global]
# TDS protocol version
tds version = 7.4
client charset = UTF-8

также убедитесь, что PHP настроен правильно:

ini_set('mssql.charset', 'UTF-8');

похоже, у вас есть this→!that, ASCII аналог UTF-8 закодирован this→!that.

положить вещи сразу после предложений, сделанных здесь, не решит всю проблему волшебным образом. Особенно если у вас уже есть данные в таблице(с) что скорее всего.

нужно, чтобы сделать новый старт чтобы найти правильный путь.

  • создайте новую таблицу с хотя бы одним столбцом nvarchar, скажем TestTable(Column1)
  • создать пустой UTF-8 закодировано -требуется для жестко закодированных входов во время тестов - PHP файл. test.php
  • на freetds.conf обязательно добавить параметр client charset = UTF-8 под [global] или . Это набор символов, используемый для связи между FreeTDS и SQL Server.


принятый ответ, кажется, делает работу; да, вы можете закодировать его в base64 и затем декодировать его снова, но затем все приложения, которые используют эту удаленную базу данных, должны изменить и поддерживать поля, чтобы быть base64 закодирован. Я думаю, что если есть удаленная база данных MS SQL Server, может быть другое приложение (или приложения), которое может ее использовать, поэтому приложение также должно быть изменено для поддержки как plain, так и base64 кодировка. И Вам также придется справиться с обоими обычный текст и base64 преобразованный текст.

Я немного поискал, и я нашел, как отправить текст UNICODE на MS SQL Server с помощью команд MS SQL и PHP для преобразования байтов UNICODE в шестнадцатеричные числа.

если вы идете в документации PHP для mssql_fetch_array (http://php.net/manual/ru/function.mssql-fetch-array.php#80076), вы увидите в комментариях довольно хорошее решение, которое преобразует текст в Unicode hex значений и передает эти данные шестигранные напрямую для MS SQL Server так:

преобразование текста Юникода в шестнадцатеричные данные

// sending data to database 
$utf8 = 'Δοκιμή με unicode → Test with Unicode';  // some Greek text for example
$ucs2 = iconv('UTF-8', 'UCS-2LE', $utf8); 

// converting UCS-2 string into "binary" hexadecimal form 
$arr = unpack('H*hex', $ucs2); 
$hex = "0x{$arr['hex']}"; 

// IMPORTANT! 
// please note that value must be passed without apostrophes 
// it should be "... values(0x0123456789ABCEF) ...", not "... values('0x0123456789ABCEF') ..." 
mssql_query("INSERT INTO mytable (myfield) VALUES ({$hex})", $link);

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

чтобы получить этот текст, вам нужно попросить MS SQL Server отправить обратно кодированный текст UNICODE следующим образом:

получение текста Unicode из MS SQL Сервер

// retrieving data from database 
// IMPORTANT! 
// please note that "varbinary" expects number of bytes 
// in this example it must be 200 (bytes), while size of field is 100 (UCS-2 chars) 

// myfield is of 50 length, so I set VARBINARY to 100
$result = mssql_query("SELECT CONVERT(VARBINARY(100), myfield) AS myfield FROM mytable", $link); 

while (($row = mssql_fetch_array($result, MSSQL_BOTH))) 
{ 
    // we get data in UCS-2 
    // I use UTF-8 in my project, so I encode it back 
    echo '1. '.iconv('UCS-2LE', 'UTF-8', $row['myfield'])).PHP_EOL; 
    // or you can even use mb_convert_encoding to convert from UCS-2LE to UTF-8
    echo '2. '.mb_convert_encoding($row['myfield'], 'UTF-8', 'UCS-2LE').PHP_EOL;
} 

таблица MS SQL с данными UNICODE после вставки

MS SQL Table

результат вывода с помощью страницы PHP для отображения значений

PHP Output

Я не уверен, что вы можете добраться до моей тестовой страницы здесь, но вы можете попробовать увидеть живые результаты: http://dbg.deve.wiznet.gr/php56/mssql/test1.php