Работа с eacute и другими специальными символами с использованием Oracle, PHP и Oci8
-
23-09-2019 - |
Вопрос
Привет, я пытаюсь сохранить имена в базе данных 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