代码之家  ›  专栏  ›  技术社区  ›  joedevon

请帮助我跟踪每一步如何处理字符集

  •  2
  • joedevon  · 技术社区  · 15 年前

    我们都知道如何 easy character sets are on the web 然而,每次你认为你做对了,一个外国字符咬你的屁股。所以我想追溯一下在下面我将描述的虚构场景中发生的事情的步骤。我会尽量把我的理解写下来,但我的问题是你们要纠正我犯下的任何错误,并填补任何空白。

    在阅读这个场景时,假设这是由John在Mac上完成的,Jane在Windows上完成的,并且在任何特定情况下,如果一个行为与另一个行为不同,则添加注释。


    我们的英雄(约翰/简)从用微软Word写一段开始。Word的字符集为空1( CP1252 ?).

    S/H复制段落,包括智能引号(例如“”)。复制操作由blank2(操作系统…windows/mac?)哪个空白3(检测应用程序正在使用什么字符集并继承该字符集?).s/he然后将段落粘贴到stackoverflow的文本框中。

    假设stackoverflow运行在apache/php上,而httpd.conf中的设置没有指定 AddDefaultCharset utf-8 他们的php.ini设置了 default_charset 至ISO-859-1。

    然而,以上两个字符集都不重要,因为堆栈溢出的头包含此语句 META http-equiv="Content-Type" content="text/html; charset=UTF-8" ,因此,即使单击“提问”时,您可能看到 firebug “内容类型文本/html;”..事实上,firefox/ie/opera/other browsers blank4(完全100%忽略服务器头并用头中的元内容类型声明覆盖它)?虽然它必须在知道内容类型之前读取该文件,但由于在显示正文之前它不必对编码做任何操作,因此这与浏览器没有区别?).

    因为页面的元内容类型是utf-8,所以输入表单会将您键入的任何字符转换为utf-8字符。blank5(如果有人能详细介绍浏览器在这一步中所做的工作,这将是非常有帮助的……这是我的理解……因为操作系统控制剪贴板和表单中字符的显示,它将字符插入到从中复制的任何字符集中。并以该字符集的形式显示它…在本例中覆盖utf-8)。

    让我们假设表单方法=get而不是post,这样我们就可以使用url浏览器输入来播放……继续我们的故事,表单以UTF-8的形式提交。智能引号代表十进制代码147&148,当浏览器将其转换为UTF-8时,它将转换为空白6个字符。

    假设在提交之后,堆栈溢出在表单中发现了一个错误,因此它不会显示结果问题,而是将问题与表单中的问题一起弹出输入框。在PHP中,表单变量用htmlspecialchars($var)转义,以便正确显示数据,因为这一次它是blank7(浏览器控制显示,而不是操作系统……因此,引号需要表示为它的utf-8等价物,否则你会得到一个可怕的有趣的问号?)

    但是,如果您使用智能引号,直接将它们插入到URL栏中,然后点击Enter…,HTMLSpecialChars将执行blank8,使表单显示混乱,并插入问号,因为直接查询URL将只使用URL中的编码…甚至是blank9(混合编码?)如果你有不止一个…

    发送请求时,浏览器将向浏览器列出可接受的字符集。字符集列表来自blank10。

    现在您可能认为我们的故事到此结束,但事实并非如此。因为stackoverflow需要将此数据保存到数据库中。幸运的是,经营这家公司的人很聪明。因此,当他们的mysql客户机连接到数据库时,它通过发出 SET NAMES UTF-8 连接启动后立即发出命令。此外,mysql的默认字符集设置为utf-8,每个字段的设置方式都相同。

    因此,stack overflow已经完全保护了他们的网站不受数据库注入、CSRF伪造和XSS站点脚本问题的影响……或者至少是那些由charset游戏带来的问题。

    *注意,这是一个例子,而不是该页面的实际响应。

    1 回复  |  直到 12 年前
        1
  •  3
  •   Jonathan Feinberg    15 年前

    我不知道这是否“回答”了你的“问题”,但我至少能帮你解决我认为可能是严重误解的问题。

    你说,“因为页面的元内容类型是utf-8,输入表单会将你输入的任何字符转换成utf-8字符。”没有“utf-8字符”这样的东西,在粘贴的时候想一想“转换”任何东西成任何东西都是不真实甚至没有意义的。字符是一个完全抽象的概念,没有办法知道(没有阅读源代码的情况下)给定的程序(包括Web浏览器)是如何决定实现它们的。由于现在最重要的应用程序都是Unicode技术,它们可能有一些内部抽象来将文本表示为Unicode字符——注意,这是 统一码 而不是 UTF-8 .

    以Unicode(或任何其他字符集)表示的一段文本表示为一系列 代码点 ,唯一分配给的整数 文字 是大型数据库中的命名实体,每个实体都具有任意数量的属性(例如,它是否是组合标记,是否从右向左移动等)。这是橡胶与道路的交汇点:为了 代表 在一台真正的计算机中,通过将其保存到一个文件中,或通过网络将其发送到另一台计算机,它必须 编码的 作为一系列字节。UTF-8是一个 编码 (或Unicode语言中的“转换格式”),将每个整数代码点表示为一个唯一的字节序列。特别是UTF-8有几个有趣和良好的特性,但它们与理解正在发生的事情无关。

    在您描述的场景中,内容类型元数据告诉浏览器如何将发送的字节解释为一系列字符(记住,这些字符是完全抽象的实体,与字节或任何东西都没有关系)。它还告诉浏览器在返回服务器的过程中,请将用户输入的文本值编码为UTF-8格式。

    所有这些评论都适用于整个链条。当一个计算机程序处理“文本”时,它是在“字符”序列上进行操作的,字符序列是表示书面语言最小组成部分的抽象。但是,当它想要将文本保存到一个文件或将其传输到其他地方时,它必须将该文本转换成一个字节序列。

    我们使用Unicode是因为它的字符集是通用的,并且因为它在编码中使用的字节序列(utf-8、utf-16s和utf-32)是明确的。

    另外,当你看到时,有两个可能的原因。

    1)程序被要求使用一些字符集(例如,ISO-8859-1)编写一些字符,这些字符集不包含出现在文本中的特定字符。因此,如果文本在内部被表示为一个Unicode代码点序列,并且文本编辑器被要求另存为ISO-8859-1,并且文本包含一些日语字符,那么它要么拒绝这样做,要么吐出一些任意的ISO-8859-1字节序列来表示“no puedo”。

    2)程序接收到一系列字节,这些字节可能在某些编码中表示文本,但它使用不同的编码来解释这些字节。有些字节序列在这种编码中没有意义,因此它可以拒绝这样做,也可以选择一些字符(如)来表示每个不可理解的字节序列。

    P.P.S.这些编码/解码舞蹈发生在您选择的操作系统中的应用程序和剪贴板之间。想象一下可能性。


    回答您的意见:

    “Word使用CP1252编码”是不正确的;它使用Unicode在内部表示文本。您可以通过将一些片假名字符(如_)粘贴到Word中来验证这一点。Windows-1252不能表示这样的字符。

    当您从任何应用程序“复制”某些内容时,完全由应用程序决定将什么内容放入剪贴板。例如,当我在Word中执行复制操作时,我看到17个不同的数据块,每个数据块都有不同的格式,放在剪贴板中。其中一个有类型cf_unicodetext,正好是utf-16。

    现在,至于URL…找到详细信息 here . 在发送HTTP请求之前,浏览器必须将URL(可以包含任何文本)转换为IRI。首先将URL编码为UTF-8,然后用百分比转义形式表示ASCII可打印范围之外的UTF-8字节,将其转换为IRI。例如,正确的编码 http://foo.com/dir1/引き割り.html http://foo.com/dir1/%E5%BC%95%E3%81%8D%E5%89%B2%E3%82%8A.html . (主机名遵循不同的规则,但都在链接到资源中)。

    现在,在我看来,浏览器应该在位置栏中显示纯旧文本,并在幕后进行所有编码。但是有些浏览器会做出愚蠢的选择,它们会向你展示IRI表单,或者是URL和IRI的奇美拉。