PHP 7 sqlsrv_fetch_array функция возвращает строки Latin1 VARCHAR в виде UTF, а НЕ требуемой Latin1 - PullRequest
0 голосов
/ 17 мая 2019

Функция "sqlsrv_fetch_array" возвращает символьные строки как UTF-8, а не как Latin1.

Строковые данные, хранящиеся в СЕРВЕРЕ MS SQL, представлены на латинице 1. Когда инструменты базы данных MS VS, AquaDataStudio и т. Д. Отображают данные VARCHAR, они отображаются как Latin1, который является типом данных в базе данных. Существующий код PHP 5 (который использует FreeTDS) также правильно отображает данные. Это важно, потому что некоторые поля содержат двоичные данные, хранящиеся в схеме кодирования Base128, в которой используются однобайтовые символы печати в диапазоне от 128 до 255, с функцией PHP ORD, используемой для декодирования в строки VARCHAR.

Теперь нам нужно перейти к PHP 7, и драйверы Microsoft (функции, начинающиеся с «sqlsrv», например «sqlsrv_connect», «sqlsrv_query», «sqlsrv_fetch_array» и т. Д.) Используются, и они НЕ возвращают строки (VARCHAR) как Latin 1, но как многобайтовый UTF-8, и, конечно, это имеет два значения: 1) возвращаемые строки символов намного длиннее исходных строк, поэтому проверки не пройдены, и / или строки обрезаются, и 2) функция PHP ORD возвращает правильное значение только для символов в десятичном диапазоне 0-127, поэтому код декодирования / дешифрования завершается неудачей.

Я создал таблицу в локальной базе данных на PHP 5, которая содержит записи для каждого символа в диапазоне 1-255. Когда я читаю записи в PHP 5 и отображаю символы и их значение «ORD ()», я вижу правильные результаты. Версия кода PHP 7 отображает символы в диапазоне 1-127 правильно, но 128-255 показывают в виде вопросительных знаков, однобайтовые символы с неправильным значением ORD () или две или три байтовые строки, где "ORD" Возвращено неверное значение.

Похоже, проблема в том, что функция "sqlsrv_fetch_array" принудительно переносит любые строковые данные в UTF-8 и возвращает только UTF-8.

Переход на UTF-8 не возможен, поскольку данные не наши, и у нас есть только доступ для чтения к базам данных.

Кроме того, приложение содержит более полумиллиона строк кода PHP 5, поэтому попытка выполнить и использовать iconv () для каждого поля, возвращаемого в каждом запросе, нецелесообразна.

Как мы можем получить данные Latin1, возвращаемые в PHP 7, из базы данных, где данные фактически хранятся в Latin1?

В PHP 7 с использованием функций Microsoft "sqlsrv" ничего из того, что я пробовал, пока не работает. Вот некоторые из вещей, которые я пробовал:

    SELECT COLLATIONPROPERTY('SQL_Latin1_General_CP1_CI_AS','CodePage')

… не имеет никакого эффекта, возможно, потому что это база данных по умолчанию.

    SELECT * FROM z_php5_charset ORDER BY id
    COLLATE Latin1_General_CP1_CI_AS

… возвращает сообщение об ошибке «Тип выражения int недопустим для предложения COLLATE». меняется на:

    COLLATE SQL_Latin1_General_CP1_CI_AS

… вернул ту же ошибку.

Думая, что это может быть как-то связано с настройками «mbstring» в файле php.ini, мы установили модуль, попробовали по крайней мере дюжину настроек, включающих вариации «English» и «ISO-8859-1» из всего установить «Английский» для всего, установленного на «ISO-8859-1», перезапуская Apache между каждым тестом комбинации, и хотя я видел несколько меньше вопросительных знаков для некоторых комбинаций, вывод все еще был UTF-8.

    mb_internal_encoding('ISO-8859-1');

… тоже не дало эффекта.

Похоже, проблема в том, что функция "sqlsrv_fetch_array" принудительно переносит любые строковые данные в UTF-8 и возвращает только UTF-8.

Minimum code (PHP 7 version)
…
    mb_internal_encoding('ISO-8859-1');
    $db_con = @sqlsrv_connect($server, $connectionInfo);
    $sql = "SELECT COLLATIONPROPERTY('SQL_Latin1_General_CP1_CI_AS','CodePage'); ".
       // 'COLLATE Latin1_General_CP1_CI_AS '.
       "\n";
    $sql = 'SELECT * FROM z_php5_charset ORDER BY id '.
       // 'COLLATE Latin1_General_CP1_CI_AS '.
       "\n";
    $result_id = sqlsrv_query($db_con, $sql, $parms, $options);
    while ($row = sqlsrv_fetch_array($result_id, SQLSRV_FETCH_ASSOC)) {
       $c = $row['id'];
       $char = $row['charset'];
       $outbuf = $c.': '.$char.'  '.ord($char);
       if (strlen($char) > 1) {
          $outbuf .= ' --- more than one char returned ['.strlen($char).' chars returned]';
       }
       echo $outbuf."\n";
    }  // end while
Please note:  

Column 1 is the ORDinal value of the character written to the VARCHAR field in the database by a PHP program.

Column 2 is the character returned when retrieved from the database.

Column 3 is the value returned by the PHP ORD() function.

column 4 (if any) is additional information about the character retrieved.

    Sample of PHP 5 output:
    160: †  160
    161: °  161
    162: ¢  162
    163: £  163
    164: §  164
    165: •  165
    166: ¶  166
    167: ß  167
    168: ®  168
    169: ©  169
    170: ™  170
    171: ´  171
    172: ¨  172
    173: ≠  173
    174: Æ  174
    175: Ø  175
    176: ∞  176
    177: ±  177
    178: ≤  178
    179: ≥  179


    Sample of PHP 7 output:
    160: Â   194 --- more than one char returned [2 chars returned]
    161: ¡  194 --- more than one char returned [2 chars returned]
    162: ¢  194 --- more than one char returned [2 chars returned]
    163: £  194 --- more than one char returned [2 chars returned]
    164: ¤  194 --- more than one char returned [2 chars returned]
    165: ¥  194 --- more than one char returned [2 chars returned]
    166: ¦  194 --- more than one char returned [2 chars returned]
    167: §  194 --- more than one char returned [2 chars returned]
    168: ¨  194 --- more than one char returned [2 chars returned]
    169: ©  194 --- more than one char returned [2 chars returned]
    170: ª  194 --- more than one char returned [2 chars returned]
    171: «  194 --- more than one char returned [2 chars returned]
    172: ¬  194 --- more than one char returned [2 chars returned]
    173: ­  194 --- more than one char returned [2 chars returned]
    174: ®  194 --- more than one char returned [2 chars returned]
    175: ¯  194 --- more than one char returned [2 chars returned]
    176: °  194 --- more than one char returned [2 chars returned]
    177: ±  194 --- more than one char returned [2 chars returned]
    178: ²  194 --- more than one char returned [2 chars returned]
    179: ³  194 --- more than one char returned [2 chars returned]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...