【问题标题】:Accents in uploaded file being replaced with '?'上传文件中的重音被替换为“?”
【发布时间】:2011-09-20 19:45:18
【问题描述】:

我正在为我正在开发的网站的管理部分构建数据导入工具。数据是法语和英语的,并且包含许多重音字符。每当我尝试上传文件、解析数据并将其存储在我的 MySQL 数据库中时,重音符号都会被替换为“?”。

我有包含数据的文本文件(字符集是 iso-8859-1),我使用 CodeIgniter 的文件上传库上传到我的服务器。然后我用 PHP 读取文件。

我的代码是这样的:

$this->upload->do_upload()
$data = array('upload_data' => $this->upload->data());

$fileHandle = fopen($data['upload_data']['full_path'], "r");

while (($line = fgets($fileHandle)) !== false) {
    echo $line;
}

这会产生用“?”替换重音的行。其他一切都是正确的。

如果我通过 FTP 从服务器下载上传的文件,字符集仍然是 iso-8850-1,但差异显示文件已更改。但是,如果我在 TextEdit 中打开文件,它会正确显示。

我尝试使用 PHP 的 stream_encoding 方法将我的文件流显式设置为 iso-8859-1,但我的 PHP 版本没有该方法。

在想法用尽后,我尝试将字符串包装在 utf8_encodeutf8_decode 中。都没有用。

如果有人对我可以尝试的事情有任何建议,我将非常感激。

【问题讨论】:

    标签: php codeigniter file-upload character-encoding diacritics


    【解决方案1】:

    重要的是查看损坏是在向 mySQL 发出查询之前还是之后发生的。这里发生了太多可能的事情,无法查明它。你能输出你的 MySql 来检查这个吗?

    假设您的查询格式正确(在输出查询的阶段没有损坏),您应该检查几件事。

    1. 数据库本身的字符编码是什么? (整理)

    2. 连接的字符集是什么 - 这可能在您的 mysql 配置中设置不正确,可以使用“SET NAMES”命令手动设置

    在我自己的应用程序中,我在建立连接后发出“SET NAMES utf8”作为我的第一个查询,因为我无法更改 MySQL 配置。

    看到这个。 http://dev.mysql.com/doc/refman/5.0/en/charset-connection.html

    编辑:如果问题与 mysql 无关,我会检查以下内容

    1. 你说文件的编码是'charset is iso-8859-1' - 请问你是怎么确定的?

    2. 如果将文件本身保存为 utf8(无 BOM)并尝试重新处理它会发生什么?

    3. 执行转换的 php 文件的编码是什么? (你用什么来写你的 php - 它可能以一种不受欢迎的方式为你“管理”它)

    4. (旁白)您正在处理的文件是否适合使用 fgetcsv 进行处理? http://php.net/manual/en/function.fgetcsv.php

    【讨论】:

    • 如果我直接回显 fgets() 读取的字符串,它们会有问号而不是重音符号。我认为问题与 MySQL 无关。
    • 我在命令行上使用file -I <filepath> 检查了文件的字符集。我正在使用 Eclipse 创建和编辑 PHP 文件,它们被编码为 ascii。我正在使用 Filezilla 上传文件,但似乎通过它保留了编码-当我下载以前上传的文件时,它们仍然具有原始字符集。
    • 根据您的 #2 建议,我使用 utf-8 编码保存了我的原始文件,并且它有效。由于我不能保证我的用户会使用这个字符集,有没有办法在文件上传时进行转换?
    • 尝试转换文件的编码。我使用 Notepad++ 来执行此操作,因为它允许在 ANSI/utf8 等notepad-plus-plus.org 之间进行简单转换。根据我的经验,50% 的编码问题归结于源文件编码不正确,50% 与数据库/连接有关。使用 NP++ 打开文件(假设您可以使用 Windows),然后从编码菜单中选择“转换为 utf-8 而不使用 BOM”。保存。尝试重新上传。看看你的进展如何。
    • @kissmyface 当我上传的文件使用 utf-8 时它可以正常工作,但是将上传的文件是从外部数据库转储的,该数据库使用 iso-8859-1 保存其导出数据(根据hakre 支持法语口音)。如果我转换文件,我需要在我的服务器上转换它。
    【解决方案2】:

    上传到您的服务器的文件应该在下载时返回相同的结果。这意味着,不应更改文件的编码(只是一堆二进制数据)。相反,您应该注意您能够不更改地存储该文件的二进制信息。

    要在您的数据库中实现这一点,请创建一个 BLOB 字段。这是正确的列类型。这只是二进制数据。

    假设您使用的是 MySQL,这是参考:The BLOB and TEXT Types,请注意 BLOB。

    【讨论】:

    • 我没有将文件存储在我的数据库中;只是我从文件中读取的字符串。
    • 数据库中字段的数据类型是什么?
    • 数据库中的字段是文本,但是在我将任何内容存储到数据库中之前,我已经失去了口音。如果我在从文件中读取字符串时回显这些字符串,则它们没有重音符号。
    • 你在哪里回应他们?你的浏览器?您是否使用hex_dump() function 检查了字节是否有序?
    【解决方案3】:

    问题是您使用的是 iso-8859-1 而不是 utf-8。为了将其编码为正确的字符集,您应该使用 iconv 函数,如下所示:

    $output_string = iconv('utf-8", "utf-8//TRANSLIT", $input_string);

    iso-8859-1 没有任何类型的重音编码。

    如果一切都是 utf-8 就更好了,因为它几乎可以处理人类已知的所有字符。

    【讨论】:

    • 我刚刚尝试使用 iconv(),但失败并出现错误“检测到输入字符串中的非法字符”。我还尝试使用 iso-8859-1 作为输入字符集。如果 iso-8859-1 没有任何类型的重音编码,它如何显示重音?像 TextEdit 这样的程序会在显示之前自动转换编码吗?
    • @Katfish:IIRC iso-8859-1 涵盖了法语口音。如果您将文件存储到数据库中,您应该将它们存储为 BLOB 并使用它们的“本机”编码按原样交付它们。在将它们存储在数据库中之前,不要按照此答案中的建议破坏它们。按原样存储它们。
    • @hakre 我只将从我的文件中读取的字符串存储在我的数据库中。文件在我解析后被删除。
    • 如果您存储字符串,它们可能会被 MySQL 破坏以匹配您的数据库/表/列编码(甚至被客户端连接到您的数据库)。将它们存储到 BLOB 字段中。 PHP 中的字符串是二进制字符串,因此您实际上是在处理二进制数据。
    • @hakre 如果我使用 BLOB 字段,PHP 是否还能像读取字符串一样读取它?
    猜你喜欢
    • 2013-08-07
    • 2012-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-18
    • 2016-10-30
    相关资源
    最近更新 更多