繁体   English   中英

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

[英]Dealing with eacute and other special characters using Oracle, PHP and Oci8

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

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

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

谢谢


更新:3 月 1 日 18:40

找到这个 function: 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 连接使用该字符集。 使用 oci8 从 PHP 检索é现在有效了! (对于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 ...所以我们将看看会发生什么,希望它能起作用。

我猜你知道这些事实:

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

您还必须知道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"

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

utf8_decode($my_sent_value)

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

echo $my_received_value

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

utf8_encode($my_received_value)

我不得不面对这个问题: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

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

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

如果服务器端代码(在本例中为 php)和 Oracle 数据库之间有不同的字符集,则应在 Oracle 连接中设置服务器端代码字符集,然后 Oracle 进行转换。

示例:让我们假设:

  • php 字符集utf-8 (默认)。
  • Oracle 字符集AMERICAN_AMERICA.WE8ISO8859P1

在由 php 建立的到 Oracle 的连接中,您应该设置UTF8 (第三个参数)。

oci_pconnect("USER", "PASS", "URL"),"UTF8");

为此,您在utf-8中编写代码(根本不进行任何转换)并通过此连接从数据库中获取utf-8

因此,您可以编写类似SELECT * FROM SOME_TABLE WHERE TEXT = 'SOME TEXT LIKE áéíóú Ñ'内容,结果还得到utf-8文本。

根据php 文档,默认情况下,Oracle 客户端 ( oci_pconnect ) 从操作系统获取NLS_LANG环境变量。 一些基于 debian 的系统没有NLS_LANG环境变量,所以我认为如果我们不指定第三个参数,Oracle 客户端将使用它自己的字符集( AMERICAN_AMERICA.WE8ISO8859P1 )。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM