Привет, Я пытаюсь сохранить имена в базе данных Oracle и вернуть их с помощью PHP и oci8.
Однако, если я вставляю é
непосредственно в базу данных Oracle и использую oci8 для его возврата, я просто получаю e
Должен ли я кодировать все специальные символы (включая é
) в html-объекты (т.е.: é
) перед вставкой в базу данных … или я чего-то не хватает?
Спасибо
ОБНОВЛЕНИЕ: 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 с помощью é
works.
Проблема на самом деле на стороне PHP. Используя инфраструктуру ExtJs, при отправке формы она кодирует ее с encodeURIComponent
.
Таким образом, é
отправляется как %C3%A9
а затем перекодируется в é
.
Однако это длина теперь 2 (strlen($my_sent_value) = 2)
а не 1. И если в PHP я пытаюсь: $ my_sent_value == é
= FALSE
Я думаю, что если я могу перекодировать все эти символы в 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 для этого … поэтому мы посмотрим, что произойдет, надеюсь, это сработает.
Я полагаю, вы знаете об этих фактах:
é
). HTML-объекты используются, ну, HTML. Oracle не является веб-браузером 😉 Вы также должны знать, что объекты HTML не привязаны к определенной кодировке; напротив, они используются для представления символов в контексте, не зависящем от набора символов.
Вы нечетко говорите об ISO-8859-1 и UTF-8. Какую кодировку вы хотите использовать? ISO-8859-1 прост в использовании, но он может хранить только текст на некоторых латинских языках (например, на испанском языке), и ему не хватает общих символов, таких как символ. UTF-8 сложнее использовать, но он может хранить все символы, определенные консорциумом Unicode (включая все, что вам когда-либо понадобится).
После того, как вы приняли решение, вы должны настроить Oracle для хранения данных в такой кодировке и выбрать соответствующий тип столбца. Например, VARCHAR2 отлично подходит для простого ASCII, NVARCHAR2 подходит для UTF-8.
Вот что я, наконец, сделал для решения этой проблемы:
Изменен профиль демона с запущенным 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)
Если вы действительно не можете изменить набор символов, который будет использовать оракул, то как насчет Base64, кодирующего ваши данные, прежде чем хранить его в базе данных. Таким образом, вы можете принимать символы из любого набора символов и хранить их как ISO-8859-1 (потому что Base64 выведет подмножество набора символов ASCII, который точно соответствует ISO-8859-1). Кодировка Base64 увеличит длину строки, в среднем, на 37%
Если ваши данные будут отображаться только как HTML, вы также можете хранить объекты HTML, как вы предполагали, но имейте в ϑ
что один объект может содержать до 10 символов на unencoded символ, например θ is ϑ
Мне пришлось столкнуться с этой проблемой: специальные символы LatinAmerican хранятся как «?» или «¿» в моей базе данных 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.
Надеюсь, это поможет … если есть что-то, чтобы улучшить PLS, не стесняйтесь публиковать свои комментарии.
Источники: http://www.nullskull.com/faq/834/convert-string-to-hex-and-hex-to-string-in-net.aspx https://forums.oracle.com/thread/44799