5

您好我正在尝试将名称存储到 Oracle 数据库中并使用 PHP 和 oci8 取回它们。

但是,如果我将其é直接插入 Oracle 数据库并使用 oci8 将其取回,我只会收到一个e

在插入数据库之前,我是否必须将所有特殊字符(包括é)编码为 html 实体(即:é)......或者我错过了什么?

谢谢


更新:3 月 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;
}

似乎工作,虽然不确定它是否是最佳解决方案


更新:3 月 8 日 15:45

Oracle 的字符集是 ISO-8859-1。
在 PHP 中我添加了:

putenv("NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1");

强制 oci8 连接使用该字符集。从 PHP 中检索éusing oci8 现在可以了!(对于varchars,但CLOBs不必utf8_encode提取它)
所以然后我尝试将数据从 PHP 保存到 Oracle ......它不起作用......从 PHP 到 Oracle 的某个地方é变成了一个?


更新:3 月 9 日 14:47

于是越来越近。添加 NLS_LANG 变量后,直接进行 oci8 插入即可é

问题实际上出在 PHP 方面。通过使用 ExtJs 框架,在提交表单时,它使用encodeURIComponent.
所以é被发送%C3%A9,然后重新编码成é.
但是它的长度现在是2 (strlen($my_sent_value) = 2)而不是 1。如果在 PHP 中我尝试: $my_sent_value == é= FALSE

我想如果我能够将 PHP 中的所有这些字符重新编码回字节大小为 1 的长度,然后将它们插入 Oracle,它应该可以工作。

虽然仍然没有运气


更新:3 月 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……所以我们将看看会发生什么,希望它可以工作。

4

4 回答 4

2

我想你知道这些事实:

  • 有许多不同的字符集:您必须选择一个,当然,还要知道您使用的是哪一个。
  • Oracle 完全能够存储没有 HTML 实体的文本 ( é)。HTML实体用于HTML。Oracle 不是 Web 浏览器 ;-)

您还必须知道 HTML 实体没有绑定到特定的字符集;相反,它们用于表示与字符集无关的上下文中的字符。

您含糊其辞地谈论 ISO-8859-1 和 UTF-8。你想使用什么字符集?ISO-8859-1 易于使用,但它只能存储某些拉丁语言(如西班牙语)的文本,并且缺少一些常见的字符,如 € 符号。UTF-8 使用起来比较棘手,但它可以存储 Unicode 联盟定义的所有字符(包括您需要的所有字符)。

做出决定后,您必须配置 Oracle 以在此类字符集中保存数据并选择适当的列类型。例如,VARCHAR2 适用于纯 ASCII,NVARCHAR2 适用于 UTF-8。

于 2010-03-03T11:06:38.023 回答
2

这就是我最终解决这个问题的方法:

将运行 PHP 的守护进程的配置文件修改为:

NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1

这样 oci8 连接使用 ISO-8859-1。

然后在我的 PHP 配置中将默认内容类型设置为 ISO-8859-1:

default_charset = "iso-8859-1"

当我通过 oci8 从 PHP 插入 Oracle 表时,我会:

utf8_decode($my_sent_value)

当从 Oracle 接收数据时,打印变量应该是这样的:

echo $my_received_value

但是,当通过 ajax 发送该数据时,我不得不使用:

utf8_encode($my_received_value)
于 2010-03-11T16:33:39.153 回答
0

如果您真的无法更改 oracle 将使用的字符集,那么在将数据存储到数据库之前如何对数据进行 Base64 编码。这样,您可以接受来自任何字符集的字符并将它们存储为 ISO-8859-1(因为 Base64 将输出完全映射到 ISO-8859-1 的 ASCII 字符集的子集)。Base64 编码将使字符串的长度平均增加 37%

如果您的数据只会显示为 HTML,那么您不妨按照您的建议存储 HTML 实体,但请注意,单个实体每个未编码字符最多可包含 10 个字符,例如 ϑ 是ϑ

于 2010-03-08T21:55:54.143 回答
0

我不得不面对这个问题:拉丁美洲的特殊字符存储为“?” 或我的 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 是从 ASP.NET 代码接收“myVariableHex”值的 Oracle 参数。

希望它有所帮助......如果有什么需要改进的地方,请不要犹豫发表您的评论。

资料来源: http ://www.nullskull.com/faq/834/convert-string-to-hex-and-hex-to-string-in-net.aspx https://forums.oracle.com/thread/44799

于 2013-10-24T21:26:32.257 回答