Работа с eacute и другими специальными символами с использованием Oracle, PHP и Oci8

StackOverflow https://stackoverflow.com/questions/2357680

Вопрос

Привет, я пытаюсь сохранить имена в базе данных Oracle и извлечь их обратно, используя PHP и oci8.

Однако, если я вставлю é непосредственно в базу данных Oracle и используйте oci8 для извлечения ее обратно, я просто получаю e

Должен ли я кодировать все специальные символы (включая é) в html -объекты (ie: é) перед вставкой в базу данных ...или я что - то упускаю ?

Спасибо


Обновить:1 марта в 18:40

нашел эту функцию:http://www.php.net/manual/en/function.utf8-decode.php#85034

function charset_decode_utf_8($string) {
    if(@!ereg("[\200-\237]",$string) && @!ereg("[\241-\377]",$string)) {
        return $string;
    }
$string = preg_replace("/([\340-\357])([\200-\277])([\200-\277])/e","'&#'.((ord('\\1')-224)*4096 + (ord('\\2')-128)*64 + (ord('\\3')-128)).';'",$string);
$string = preg_replace("/([\300-\337])([\200-\277])/e","'&#'.((ord('\\1')-192)*64+(ord('\\2')-128)).';'",$string);
return $string;
}

кажется, работает, хотя и не уверен, что это оптимальное решение


Обновить:8 марта в 15:45

Набор символов Oracle - ISO-8859-1.
в PHP я добавил:

putenv("NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1");

чтобы заставить соединение oci8 использовать этот набор символов.Извлечение é использование oci8 из PHP теперь сработало !(для varchars, но не CLOBs пришлось сделать utf8_encode чтобы извлечь его )
Итак , затем я попытался сохранить данные из PHP в Oracle ...и это не работает .. где-то на пути от PHP к Oracle é становится ?


Обновить:9 марта в 14:47

Итак, становимся ближе.После добавления переменной NLS_LANG, выполнение прямых вставок oci8 с é работает.

Проблема на самом деле находится на стороне PHP.Используя фреймворк ExtJS, при отправке формы он кодирует ее с помощью encodeURIComponent.
Итак é отправляется как %C3%A9 а затем перекодирован в é.
Однако теперь его длина равна 2 (strlen($my_sent_value) = 2) и не 1.И если в PHP я попытаюсь:$my_sent_value == $my_sent_value == é = ЛОЖЬ

Я думаю, что если я смогу перекодировать все эти символы в PHP обратно в длины размером в 1 байт, а затем вставить их в Oracle, это должно сработать.

Однако по-прежнему безуспешно


Обновить:10 марта в 11:05

Я продолжаю думать, что я так близко (и в то же время так далеко).

putenv("NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P9"); работает очень нерегулярно.

Я создал небольшой php-скрипт для тестирования:

header('Content-Type: text/plain; charset=ISO-8859-1');
putenv("NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P9");
$conn= oci_connect("user", "pass", "DB");
$stmt = oci_parse($conn, "UPDATE temp_tb SET string_field = '|é|'");
oci_execute($stmt, OCI_COMMIT_ON_SUCCESS);

Запустив это один раз и войдя непосредственно в базу данных Oracle, я вижу, что STRING_FIELD имеет значение |¿|.Очевидно, это не то, чего я ожидал от своего предыдущего опыта.
Однако, если я дважды быстро обновлю эту PHP-страницу....это сработало !!!
В Oracle я правильно увидел |é|.

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

Мой следующий эксперимент заключается в экспорте переменной в среду PHP, однако мне нужно сбросить Apache для that...so посмотрим, что произойдет, надеюсь, это сработает.

Это было полезно?

Решение 2

Это то, что я в конце концов сделал, чтобы решить эту проблему:

Изменил профиль демона, работающего на PHP, чтобы иметь:

NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1

Так что соединение oci8 использует ISO-8859-1.

Затем в моей конфигурации PHP установите тип содержимого по умолчанию на ISO-8859-1:

default_charset = "iso-8859-1"

Когда я вставляю в таблицу Oracle через oci8 из PHP, я делаю:

utf8_decode($my_sent_value)

И при получении данных от Oracle печать переменной должна работать просто так:

echo $my_received_value

Однако при отправке этих данных через ajax мне пришлось использовать:

utf8_encode($my_received_value)

Другие советы

Я полагаю, вам известны эти факты:

  • Существует много различных наборов символов:вы должны выбрать один из них и, конечно же, знать, какой из них вы используете.
  • Oracle вполне способна хранить текст без HTML-объектов (é).HTML-объекты используются, ну, в общем, в HTML.Oracle - это не веб-браузер ;-)

Вы также должны знать, что HTML-объекты не привязаны к определенному набору символов;напротив, они используются для представления символов в контексте, не зависящем от кодировки.

Вы невнятно говорите об ISO-8859-1 и UTF-8.Какую кодировку вы хотите использовать?ISO-8859-1 прост в использовании, но он может хранить текст только на некоторых латинских языках (например, на испанском) и в нем отсутствуют некоторые распространенные символы, такие как символ €.UTF-8 сложнее в использовании, но он может хранить все символы, определенные консорциумом Unicode (которые включают в себя все, что вам когда-либо понадобится).

После того как вы приняли решение, вы должны настроить Oracle для хранения данных в такой кодировке и выбрать соответствующий тип столбца.Например, VARCHAR2 подходит для обычного ASCII, NVARCHAR2 подходит для UTF-8.

Если вы действительно не можете изменить набор символов, который будет использовать oracle, то как насчет кодирования ваших данных в Base64 перед сохранением их в базе данных?Таким образом, вы можете принимать символы из любого набора символов и сохранять их как ISO-8859-1 (поскольку Base64 выведет подмножество набора символов ASCII, которое точно соответствует ISO-8859-1).Кодировка Base64 увеличит длину строки в среднем на 37%

Если ваши данные будут отображаться только в формате HTML, то вы также можете сохранить HTML-объекты, как вы предложили, но имейте в виду, что один объект может содержать до 10 символов на один некодированный символ, напримерϑ является ϑ

Мне пришлось столкнуться с этой проблемой :латиноамериканские специальные символы хранятся как "?" или "¿" в моей базе данных Oracle ...Я не могу изменить NLS_CHARACTER_SET, потому что мы не являемся владельцами базы данных.

Итак, я нашел обходной путь :

1) ASP.NET код Создайте функцию, которая преобразует строку в шестнадцатеричные символы:

    public string ConvertirStringAHex(String input)
    {
        Encoding encoding = System.Text.Encoding.GetEncoding("ISO-8859-1");
        Byte[] stringBytes = encoding.GetBytes(input);
        StringBuilder sbBytes = new StringBuilder(stringBytes.Length);
        foreach (byte b in stringBytes)
        {
            sbBytes.AppendFormat("{0:X2}", b);
        }
        return sbBytes.ToString();
    }

2) Примените описанную выше функцию к переменной, которую вы хотите закодировать, следующим образом

     myVariableHex = ConvertirStringZHex( myVariable );

В ORACLE используйте следующее:

 PROCEDURE STORE_IN_TABLE( iTEXTO IN VARCHAR2 )
 IS
 BEGIN
   INSERT INTO myTable( SPECIAL_TEXT )  
   VALUES ( UTL_RAW.CAST_TO_VARCHAR2(HEXTORAW( iTEXTO ));
   COMMIT;
 END;

Конечно, itextoявляется параметром Oracle, который получает значение "myVariableHex" из ASP.NET кода.

Надеюсь , это поможет ...если есть что улучшить, пожалуйста, не стесняйтесь оставлять свои комментарии.

Источники:http://www.nullskull.com/faq/834/convert-string-to-hex-and-hex-to-string-in-net.aspx https://forums.oracle.com/thread/44799

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top