使用Oracle,PHP和Oci8处理eacute和其他特殊字符

时间:2010-03-01 17:23:13

标签: php oracle utf-8 character-encoding oci8

您好我正在尝试将名称存储到Oracle数据库中,并使用PHP和oci8将其恢复。

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

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

THX


更新: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中使用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 个答案:

答案 0 :(得分: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。

答案 1 :(得分:2)

这是我最终为解决这个问题而做的事情:

修改运行PHP的守护程序的配置文件:

NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1

因此oci8连接使用ISO-8859-1。

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

default_charset = "iso-8859-1"

当我从PHP通过oci8插入Oracle表时,我这样做:

utf8_decode($my_sent_value)

当从Oracle接收数据时,打印变量应该正常工作:

echo $my_received_value

然而,当通过ajax发送数据时,我不得不使用:

utf8_encode($my_received_value)

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

我不得不面对这个问题: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参数,它从ASP.NET代码接收“myVariableHex”的值。

希望它有所帮助...如果有什么需要改进的话请不要犹豫发表您的意见。

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