pgSQL "ERROR: invalid byte sequence for encoding "UTF8": 0x86" while parsing e-mail
pgSQL "ERROR: invalid byte sequence for encoding "UTF8": 0x86" while parsing e-mail
我正在将我的票务系统迁移到 pgSQL。我允许电子邮件回复,其中 PHP 将每封电子邮件解析为其组件,然后将消息存储在名为 inbox 的 pgSQL table 中。
第一封邮件解析成功,保存成功。没有错误。现在我收到错误消息
invalid byte sequence for encoding "UTF8": 0x86
我已确认数据库使用的是 UTF8 编码:
- SHOW SERVER_ENCODING 给出 UTF8 的结果
- SHOW CLIENT_ENCODING 最初不是 UTF8。我将其设置为UTF8。
错误仍然存在。
email_queue.php 包含各种 PHP 类 和接收和发送电子邮件的功能。命令"file email_queue.php"给出结果:
email_queue.php: PHP script, UTF-8 Unicode text, with very long lines
email_queue_receive.php 使用 类 和功能来接收电子邮件。此文件包含 email_queue.php 功能。命令"file email_queue_receive.php"给出结果:
email_queue_receive.php: PHP script, ASCII text
根据我所做的搜索,ASCII 是有效的 UTF8。
由于解析电子邮件,我还没有找到特定于此错误的讨论帖。
PostgreSQL 对编码很严格,但电子邮件基础设施不是。
正如 PHP 的 iconv_mime_decode 的文档所示:
ICONV_MIME_DECODE_STRICT If set, the given header is decoded in full
conformance with the standards defined in » RFC2047. This option is
disabled by default because there are a lot of broken mail user agents
that don't follow the specification and don't produce correct MIME
headers.
电子邮件正文中还有一些 MIME 部分违反了 Content-Type
声明中宣传的字符。只要可以将无效邮件路由到收件人,SMTP 服务器就会接受它,因此发件人不会意识到这个问题,必须由收件人来处理。
因此,必须事先对必须插入数据库文本字段的电子邮件消息的任何部分进行清理。例如,请参阅 Remove non-utf8 characters from string 如何操作。
(Daniel 说得对,只是详细说明):
0x86 不能是 utf-8 序列中的第一个字节。
可能的解释包括:
- 电子邮件不是 utf-8 编码
- 电子邮件采用 utf-8 编码,但电子邮件中的 utf-8 格式不正确
- 非 utf-8 感知子字符串代码正在 utf-8 序列中的无效字节偏移处剪切字符串
- 您的应用对 MIME 部分的编码处理不当
- ...
一般来说,将电子邮件插入 PostgreSQL 会遇到问题,因为 PostgreSQL 对文本编码的正确性非常严格,而邮件客户端会产生并接受各种可怕的垃圾。您将需要清理传入邮件(使用编码猜测、剥离可疑 parts/chars 等)或将其以原始字节序列形式存储为 bytea
.
我强烈建议存储为 bytea
因为:
- 一个 MIME 邮件可以包含不同编码的部分
- 如果电子邮件附件等 MIME 部分没有
Content-Transfer-Encoding
,则可以发送包含 NULL 字节的内容,但大多数客户端不会这样做,并且会对它们进行 base64 编码。 PostgreSQL 的 text
类型不能存储空字节。
当然,这在很大程度上取决于您要处理的内容。您可能更愿意存储为 text
并丢弃无法使用其声明的文本编码进行解码的部分。
我正在将我的票务系统迁移到 pgSQL。我允许电子邮件回复,其中 PHP 将每封电子邮件解析为其组件,然后将消息存储在名为 inbox 的 pgSQL table 中。
第一封邮件解析成功,保存成功。没有错误。现在我收到错误消息
invalid byte sequence for encoding "UTF8": 0x86
我已确认数据库使用的是 UTF8 编码: - SHOW SERVER_ENCODING 给出 UTF8 的结果 - SHOW CLIENT_ENCODING 最初不是 UTF8。我将其设置为UTF8。
错误仍然存在。
email_queue.php 包含各种 PHP 类 和接收和发送电子邮件的功能。命令"file email_queue.php"给出结果:
email_queue.php: PHP script, UTF-8 Unicode text, with very long lines
email_queue_receive.php 使用 类 和功能来接收电子邮件。此文件包含 email_queue.php 功能。命令"file email_queue_receive.php"给出结果:
email_queue_receive.php: PHP script, ASCII text
根据我所做的搜索,ASCII 是有效的 UTF8。
由于解析电子邮件,我还没有找到特定于此错误的讨论帖。
PostgreSQL 对编码很严格,但电子邮件基础设施不是。 正如 PHP 的 iconv_mime_decode 的文档所示:
ICONV_MIME_DECODE_STRICT If set, the given header is decoded in full conformance with the standards defined in » RFC2047. This option is disabled by default because there are a lot of broken mail user agents that don't follow the specification and don't produce correct MIME headers.
电子邮件正文中还有一些 MIME 部分违反了 Content-Type
声明中宣传的字符。只要可以将无效邮件路由到收件人,SMTP 服务器就会接受它,因此发件人不会意识到这个问题,必须由收件人来处理。
因此,必须事先对必须插入数据库文本字段的电子邮件消息的任何部分进行清理。例如,请参阅 Remove non-utf8 characters from string 如何操作。
(Daniel 说得对,只是详细说明):
0x86 不能是 utf-8 序列中的第一个字节。
可能的解释包括:
- 电子邮件不是 utf-8 编码
- 电子邮件采用 utf-8 编码,但电子邮件中的 utf-8 格式不正确
- 非 utf-8 感知子字符串代码正在 utf-8 序列中的无效字节偏移处剪切字符串
- 您的应用对 MIME 部分的编码处理不当
- ...
一般来说,将电子邮件插入 PostgreSQL 会遇到问题,因为 PostgreSQL 对文本编码的正确性非常严格,而邮件客户端会产生并接受各种可怕的垃圾。您将需要清理传入邮件(使用编码猜测、剥离可疑 parts/chars 等)或将其以原始字节序列形式存储为 bytea
.
我强烈建议存储为 bytea
因为:
- 一个 MIME 邮件可以包含不同编码的部分
- 如果电子邮件附件等 MIME 部分没有
Content-Transfer-Encoding
,则可以发送包含 NULL 字节的内容,但大多数客户端不会这样做,并且会对它们进行 base64 编码。 PostgreSQL 的text
类型不能存储空字节。
当然,这在很大程度上取决于您要处理的内容。您可能更愿意存储为 text
并丢弃无法使用其声明的文本编码进行解码的部分。