【发布时间】: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 => 1,我的测试操作得到了改进:元音变音被正确保存和显示,我对“狗”的测试搜索工作正常。但是,表情符号现在保存为四个问号。mysql_enable_utf8mb4设置在我的环境中似乎不可用。它完全没有效果。 -
@ikegami 通过测试,我确定我的环境不支持
mysql_enable_utf8mb4。不知道该怎么做。 -
Re "你的代码没有帮助",呃,
use open ':std', ':encoding(UTF-8)';确实binmode(STDOUT, ":encoding(UTF-8)");