【问题标题】:Unicode support (including emoji) in web application with accent insensitive collationWeb 应用程序中的 Unicode 支持(包括表情符号),带有不区分重音的排序规则
【发布时间】:2019-12-23 16:46:00
【问题描述】:

我有一个使用 Perl、CGI 和 MySQL 5.5.62 的旧版 Web 应用程序。在客户填写的字段中,我需要支持他们在输入中经常使用的变音符号和表情符号。

为了学习,我设置了以下独立测试。 (它故意非常简单,并且缺乏对输入的基本安全检查。)

转储数据库widget:

DROP TABLE IF EXISTS `experiment`;
CREATE TABLE `experiment` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(40) CHARACTER SET utf8mb4 DEFAULT NULL,
  `content` text CHARACTER SET utf8mb4,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

LOCK TABLES `experiment` WRITE;
INSERT INTO `experiment` VALUES (1,'Record','Now is the time for all good men to come to the aid of their country. 😀\r\nThe quick brown fox jumped over the lazy dög.');
UNLOCK TABLES;

Perl 代码:

#!/usr/bin/perl -T

use strict;
use warnings;

use DBI;
use CGI '-utf8';

my $dbh = DBI->connect('DBI:mysql:widget','test','test', { mysql_enable_utf8 => 0,}) or die "Can't connect to the database: $DBI::errstr";
my $sth = $dbh->prepare('SELECT * FROM `experiment`') or die "Couldn't prepare statement: " . $dbh->errstr;
$sth->execute or die "Can't execute SQL statement: $DBI::errstr";
my $hashref = $sth->fetchrow_hashref or die "Can't fetchrow_hashref: $DBI::errstr\n";
$sth->finish;
my $search = '';
for my $i (qw(fox dog)) {
    $sth = $dbh->prepare("SELECT * FROM `experiment` WHERE `content` LIKE '%$i%'") or die "Couldn't prepare statement: " . $dbh->errstr;
    my $count = $sth->execute or die "Can't execute SQL statement: $DBI::errstr";
    $search .= "<h6>String: [$i] found [$count]</h6>";
}
$sth->finish;

my $action = CGI::param('action') || '';
if ($action eq 'save') {
    my $new = CGI::param('value') || '';
    $sth = $dbh->prepare("UPDATE `experiment` SET `content` = '$new' WHERE `id` = 1") or die "Couldn't prepare statement: " . $dbh->errstr;
    $sth->execute or die "Can't execute SQL statement: $DBI::errstr";
    $sth->finish;
    print "Location: http://simulated-domain-name.com/cgi-bin/test.cgi\n\n";
    exit;
}
$dbh->disconnect;
print <<EOF;
Content-type: text/html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <!-- not part of the experiment, just make it look nice -->
    </head>
    <body>
        <div class="container my-3">
            <h5>Content = $hashref->{content}</h5>
$search
            <form method="post">
                <input type="hidden" name="action" value="save">
                <div class="form-group">
                    <label class="font-weight-bold" for="exampleFormControlTextarea1">Content</label>
                    <textarea name="value" class="form-control" id="exampleFormControlTextarea1" rows="3">$hashref->{content}</textarea>
                </div>
                <button type="submit" class="btn btn-primary">Submit</button>
            </form>
        </div>
    </body>
</html>
EOF
exit;

据我所知,use CGI 所在行的'-utf8' 无效。

当使用mysql_enable_utf8 = 0 时,程序运行良好不区分重音的搜索失败。元音变音和表情符号在浏览器中正确显示。

输出:

内容 = 现在是所有好人都来援助他们国家的时候了。 ???敏捷的棕色狐狸跳过了懒惰的狗。 字符串:[fox] 找到 [1] 字符串:[dog] 找到 [0E0]

使用 `mysql_enable_utf8 = 1' 时,HTML 输出看起来很乱。

输出:

内容 = 现在是所有好人都来援助他们国家的时候了。 ðŸ∼€ 敏捷的棕色狐狸跳过了懒惰的 dög。 字符串:[fox] 找到 [1] 字符串:[dog] 找到 [0E0]

我觉得我很接近,但错过了一些重要的事情。

【问题讨论】:

  • 查看文档我认为您想要 mysql_enable_utf8mb4 而不是 mysql_enable_utf8?如果你正在写出 Unicode 文本,你应该通过use open ':std', ':encoding(UTF-8)'; 或类似的方式告诉 Perl 标准输出应该使用 utf-8。
  • 相关表情符号的编码是4字节长,所以肯定需要mysql_enable_utf8mb4。这是唯一的问题吗?
  • @Shawn 您的代码没有帮助,但 binmode(STDOUT, ":encoding(UTF-8)"); 有帮助。使用mysql_enable_utf8 =&gt; 1,我的测试操作得到了改进:元音变音被正确保存和显示,我对“狗”的测试搜索工作正常。但是,表情符号现在保存为四个问号。 mysql_enable_utf8mb4 设置在我的环境中似乎不可用。它完全没有效果。
  • @ikegami 通过测试,我确定我的环境不支持mysql_enable_utf8mb4。不知道该怎么做。
  • Re "你的代码没有帮助",呃,use open ':std', ':encoding(UTF-8)'; 确实binmode(STDOUT, ":encoding(UTF-8)");

标签: mysql perl unicode


【解决方案1】:

表情符号 --> CHARACTER SET utf8mb4.

不区分重音 --> 任何COLLATION utf8mb4_..._ci

由于你是在比较老的 5.5 上,你可能会遇到“767 问题”。见http://mysql.rjweb.org/doc.php/limits#767_limit_in_innodb_indexes

如果您有问号或 Mojibake(例如 dög 代表 dög),请参阅 Trouble with UTF-8 characters; what I see is not what I stored

我的 Perl 笔记:

use utf8;
use open ':std', ':encoding(UTF-8)';
my $dbh = DBI->connect("dbi:mysql:".$dsn, $user, $password, {
   PrintError => 0,
   RaiseError => 1,
   mysql_enable_utf8 => 1,  # Switch to UTF-8 for communication and decode.
});
# or {mysql_enable_utf8mb4 => 1} if using utf8mb4

(我在use CGI上没有任何注释。)

【讨论】:

  • 通过测试,我确定我的堆栈不支持mysql_enable_utf8mb4。 CentOS 7 上的 Yum 说 perl-DBI-1.627-4.el7.x86_64 和 perl-DBD-MySQL-4.023-6.el7.x86_64 已经安装并且是最新版本。不知道如何继续。
  • 我只是在看那个。我认为我的问题是 yum 存储库是 4.023,我需要 DBD::mysql 4.050 来支持mysql_enable_utf8mb4。我想我会卸载存储库并手动安装新版本。
  • 那已经很老了。我有一个our $VERSION = '4.033'; 的文件,版权为 2013。
  • @TimothyB。 - 你可以从 cpan 安装,绕过yum
【解决方案2】:

这是在 CentOS 7 上为我工作的解决方案:

  • 安装 mysql-devel(通过 yum),因为 mysql_config 不在我的系统上
  • 将 Perl DBD::mysql 从 4.023(通过 yum)升级到 4.050(通过 CPAN)
  • DBI-&gt;connect 中使用mysql_enable_utf8mb4 选项
  • 在 Perl 脚本顶部添加 binmode(STDOUT, ":encoding(UTF-8)");

现在输出如预期:

内容 = 现在是所有好人都来援助他们国家的时候了。 ? 敏捷的棕色狐狸跳过了懒惰的狗。 字符串:[fox] 找到 [1] 字符串:[dog] 找到 [1]

【讨论】:

    猜你喜欢
    • 2012-06-15
    • 2016-02-02
    • 2017-06-19
    • 1970-01-01
    • 1970-01-01
    • 2021-11-05
    • 2011-05-23
    • 1970-01-01
    • 2012-07-06
    相关资源
    最近更新 更多