MySQL 因卷曲(智能)引号而窒息

Posted

技术标签:

【中文标题】MySQL 因卷曲(智能)引号而窒息【英文标题】:MySQL choking on curly (smart) quotes 【发布时间】:2010-11-22 01:50:40 【问题描述】:

我正在将一些数据从表单插入到数据库中。我正在使用addslashes 来转义文本(也尝试过mysql_real_escape_string,结果相同)。

正则引号会被转义,但其他一些引号不会。例如字符串:

荷马的血成为 Moe 新啤酒的秘密成分。

转换为:

荷马的血液成为 Moe 新啤酒的秘密成分。

我认为不转义的大引号并不重要,但只有这个文本被插入到数据库中:

荷马的血成为萌的秘密成分

所以 php 认为花引号很好,但 MySQL 正在丢失字符串。 MySQL 没有给出任何错误。

【问题讨论】:

好问题,我想知道准备好的语句是否会发生这种情况。 @Alllain:我不会这么认为,但如果有人想测试,请继续。我应该明确表示我确实知道准备好的语句,这是一些直到最近才在 PHP 4 上运行的旧代码。 【参考方案1】:

Moe's 中的 ' 是示例字符串中唯一无效的字符,如果该字符串是 latin1 编码但您的 mysql 服务器需要 utf8。

简单演示:

<?php
function foo($s) 
    echo 'len=', strlen($s), ' ';
  for($i=0; $i<strlen($s); $i++) 
    printf('%02X ', ord($s[$i]));
  
  echo "\n";


 // my file is latin1 encoded and so is the string literal
foo('Moe’s');
// now try it with an utf8 encoded string
foo( utf8_encode('Moe’s') );

打印

len=5 4D 6F 65 92 73 len=6 4D 6F 65 C2 92 73

因此问题是:您是否以“错误”的编码向 mysql 服务器提供某些内容? 每个连接都有一个连接字符集,mysql 服务器希望您的客户端(php 脚本)发送以该字符集编码的数据。你可以找出连接字符集是什么

SHOW VARIABLES LIKE '%character%'

喜欢

$mysql = mysql_connect('..', '..', '..') or die(mysql_error());
mysql_select_db('..', $mysql) or die(mysql_error());

$query = "SHOW VARIABLES like '%character%'";
$result = mysql_query($query, $mysql) or die(__LINE__.mysql_error());
while( false!==($row=mysql_fetch_array($result, MYSQL_ASSOC)) ) 
  echo join(', ', $row), "\n";

这应该打印类似的东西

character_set_client, utf8
character_set_connection, utf8
character_set_database, latin1
character_set_filesystem, binary
character_set_results, utf8
character_set_server, utf8
character_set_system, utf8

character_set_connection, utf8表示“我的”连接字符集是utf8,即mysql服务器需要来自客户端(php)的utf8编码字符。什么是“你的”连接字符集?

然后看看你的参数字符串的实际编码,即如果你有

$foo = mysql_real_escape_string($_POST['foo'], $mysql);

替换为

echo '<div>Debug hex($_POST[foo])=';
for($i=0; $i<strlen($s); $i++) 
    printf('%02X ', ord($_POST['foo'][$i]));

echo "</div>\n";
$foo = mysql_real_escape_string($_POST['foo'], $mysql);

并检查输入字符串的实际编码是什么。它是打印 92 还是 C2 92?

【讨论】:

【参考方案2】:

我会寻找您的 Web 界面中使用的字符编码与数据库级别使用的字符编码之间的不匹配。例如,如果您的 Web 界面使用 UTF-8,并且您的数据库使用默认的 MySQL 编码 latin1,那么您需要使用 DEFAULT CHARSET=utf8 设置表。

顺便说一句,使用mysql_real_escape_string() 或mysqli。 addslashes() 足以防止 SQL 注入。

【讨论】:

+1 加斜线不应该用于任何事情。确实会是字符集问题;鉴于引号字符实际上正在消失,我的猜测是它们是将 ISO-8859-1 字节插入到 UTF-8 数据库中。你真的想把所有东西都放在 UTF-8 中;首先使用该编码为您的页面提供服务,这将确保提交的表单也以 UTF-8 格式输入。 是的,因为网页不是 UTF8 而 MySQL 是。附带的问题:mysql_real_escape_string 有相反的功能吗?我在手册中找不到任何内容。 不。可能是因为很难想象你为什么需要一个。如果您要从 MySQL 中提取数据,希望很明显您不需要反转转义。如果由于某种原因您在将原始数据推送到 MySQL 之前需要原始数据,则在制作转义版本时不要删除原始数据。 这是因为我有一个函数可以递归地添加/删除斜杠(参见***.com/questions/1216552/…)。这个想法是在提交后将所有表单数据带到一致的状态,例如删除魔术引号,必要时处理数据,然后将它们添加回 MySQL 查询。不过我想我很快就会切换到参数化查询,这样可以省去很多麻烦! 啊,好吧。 IMO 对魔术引号唯一有价值的事情是删除它们,因此您只需要 stripslashes() 即可。 :)

以上是关于MySQL 因卷曲(智能)引号而窒息的主要内容,如果未能解决你的问题,请参考以下文章

仅针对文本而非 HTML 代码将哑引号转换为智能引号

卷曲工作,但 python 请求因 SSLError 而失败

摘得人工智能“奥斯卡”的为何是它们,AI的未来会因它们而改变吗?

智能盒子EasyNVR硬件设备因用户网络问题而无法分配DHCP的解决步骤

一半人将因人工智能失业?麻省理工科学家表示太可笑!

jquery在ei中的引号上附加窒息