Получение данных с кодировкой UTF-8 с сервера MSSQL с использованием расширения PHP FreeTDS

Я не могу получить данные из MSSQL, закодированные как UTF-8, с использованием расширения FreeTDS.

Подключение:

ini_set('mssql.charset', 'UTF-8');
$this->_resource = mssql_connect($config['servername'], $config['username'], $config['password']);

У меня нет возможности использовать любое другое расширение.

Я пытался создать ~/.freetds.conf

[global]
client charset = UTF-8

Я пробовал передавать параметры в php:

php -d mssql.charset="UTF-8" index.php

Данные по-прежнему не в UTF-8.

php -я

mssql

MSSQL Support => enabled
Active Persistent Links => 0
Active Links => 0
Library version => FreeTDS

Directive => Local Value => Master Value
mssql.allow_persistent => On => On
mssql.batchsize => 0 => 0
mssql.charset => no value => no value
mssql.compatability_mode => Off => Off
mssql.connect_timeout => 5 => 5
mssql.datetimeconvert => On => On
mssql.max_links => Unlimited => Unlimited
mssql.max_persistent => Unlimited => Unlimited

Идеи?


person Marius Grigaitis    schedule 14.11.2012    source источник


Ответы (8)


MSSQL и UTF-8 - это настоящая боль ... иногда. Пришлось конвертировать вручную. Проблема: MSSQL на самом деле не знает и не поддерживает UTF-8.

Преобразование из значения базы данных в UTF-8:

mb_detect_encoding($value, mb_detect_order(), true) === 'UTF-8' ? $value : mb_convert_encoding($value, 'UTF-8');

Преобразование из UTF-8 в значение базы данных:

mb_convert_encoding($value, 'UCS-2LE', mb_detect_encoding($value, mb_detect_order(), true));

К счастью, я использовал Doctrine, поэтому все, что у меня было, это создать собственную реализацию StringType.

person Louis Huppenbauer    schedule 14.11.2012
comment
MS SqlServer использует кодировку UCS2-LE, а не CP1252. Также не ISO8859-1 (подмножество CP1252). Не UTF-16 (появился после UCS2) или «Unicode» (WideChar/UTF-16 на Win). - person Henrik; 25.01.2014
comment
Вы спасли мою жизнь. Я отвечу на мой вопрос о том, как использовать это с CodeIgniter - person manuman94; 27.12.2017

У меня была аналогичная проблема, и я перепробовал все настройки, которые мог найти в Интернете, - напрасно.

В моем случае проблема заключалась в настройке самой FreeTDS. В Linux это файл /etc/freetds/freetds.conf.

Мне пришлось изменить версию на 7.0 (возможно, другие номера тоже работают. Я только что попробовал 7.0)

[global]
    # TDS protocol version
    tds version = 7.0

После этого драйвер вроде как принял изменения кодировки.

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

Кстати: изменение сразу же вступает в силу, после этого не нужно ничего перезапускать.

person mschraudolph    schedule 14.12.2012
comment
миллион благодарностей пользователю @user1903844. Эти решения помогли мне с Ubuntu+MS SQL+PHP - person Bakhtiyor; 03.09.2013
comment
Версия ›= 7.0 требуется для установки параметра конфигурации client charset = UTF-8, что может быть причиной того, что решение OP Marius Grigaitis, использующее его, не сработало. См. этот пример для freetds.conf: gist.github.com/johnkary/6643856 - person John Kary; 21.09.2013
comment
Да, наконец-то рабочий ответ! Раскомментировал строку, изменил значение на 7.0 и все заработало. Не нужна часть ini_set. - person Hannes Schneidermayer; 13.05.2014
comment
Здорово. Работающий! Вероятно, FreeTDS версии 7.0 поддерживает автоматическое преобразование между форматом клиента (UTF-8, ISO-8859-1 или что-то еще) и UCS2-LE (кодировка MSSQL), так что это прозрачно для программиста. - person Marco Marsala; 11.12.2015
comment
Это все еще не работает для меня на Xenial Xerus, PHP 7, MSSQL 2008, FreeTDS v0.91 - person katalin_2003; 10.11.2016

Если вы используете freeTDS, вы должны изменить следующие строки на /etc/freetds/freetds.conf:

[global]
# TDS protocol version
tds version = 4.2

К этому:

[global]
# TDS protocol version
tds version = 8.0
;tds version = 4.2

и, наконец, добавьте эту строку:

# set charset
client charset = UTF-8

** кодировка clinet находится в глобальном масштабе [scope]

В своих запросах вы должны использовать символ N. так:

$query = "INSERT INTO dbo.SMSOutbox (StationID, Dest, Text) VALUES ";
   $query .= '(';
   $query .= "'" . $this->stationId . "', ";
   $query .= "'" . $this->destination . "', ";
   $query .= "N'" . $this->text . "'";
   $query .= ')';
person Moe Far    schedule 26.02.2015
comment
Это решило это для меня в сочетании с преобразованиями @louis-huppenbauer. - person barryvanveen; 17.07.2017

Вы также можете решить эту проблему, добавив CharacterSet UTF-8 в $connectionInfo перед подключением к БД.

$serverName = "MyServer";
$connectionInfo = array( "Database"=>"AdventureWorks", "CharacterSet" => "UTF-8");
$conn = sqlsrv_connect( $serverName, $connectionInfo);

Работал нормально, никаких дополнительных кодировок не требовалось.

person Magnus Johansson    schedule 17.06.2014
comment
Я не могу поверить, что это не принятый ответ, сработало просто отлично, и это так легко сделать. если бы я мог дать вам больше, чем просто +1, я бы - person Shocklo; 10.11.2015
comment
Круто, спасибо за этот ответ, я искал решение, и это работает отлично. - person Justin Hanley; 21.03.2016
comment
Я абсолютно согласен; это должен быть принятый ответ! - person Stijnster; 15.06.2018
comment
Этот ответ верен для библиотеки SQLSRV от Microsoft, но неверен для библиотеки FreeTDS, о которой специально спрашивал автор. - person serverSentinel; 26.11.2020

Кажется, требуется версия 7.0 или выше. iconv() также работает хорошо, но утомительно.

$query = $this->db->query($sql);
$result = $query->fetchAll(PDO::FETCH_OBJ);
foreach ($result as $row) {
    foreach (get_object_vars($row) as $key => $value) {
    $row->$key = (mb_detect_encoding($value, mb_detect_order(), true) === 'UTF-8') 
            ? $value : iconv('iso-8859-1', 'utf-8', $value);
    }
    $results[] = $row;
}
person jjwdesign    schedule 14.08.2014
comment
Это работает! Я говорю, потому что иногда люди игнорируют ответы без слишком большого количества голосов. - person WhiteFloater; 11.02.2018

У меня была эта проблема, и она была решена путем добавления этой строки в мой php-скрипт перед подключением к MSSQL Server:

ini_set('mssql.charset', 'UTF-8');
person Sina    schedule 25.07.2015

Вы должны изменить свою версию TDS в зависимости от того, какую версию SQL-сервера вы используете. Подробности смотрите в руководстве по установке.

http://www.freetds.org/userguide/choosingtdsprotocol.htm

person bstory    schedule 02.11.2017

Я использовал то же, что и выше, но Windows 1250, поэтому:

$query = $this->db->query($sql);
$result = $query->fetchAll(PDO::FETCH_OBJ);
foreach ($result as $row) {
    foreach (get_object_vars($row) as $key => $value) {
    $row->$key = (mb_detect_encoding($value, mb_detect_order(), true) === 'UTF-8') 
            ? $value : iconv('windows-1250', 'utf-8', $value);
    }
    $results[] = $row;
}

И тогда это сработало, но я использую полированные символы

person Kordik    schedule 21.01.2020