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 因卷曲(智能)引号而窒息的主要内容,如果未能解决你的问题,请参考以下文章
卷曲工作,但 python 请求因 SSLError 而失败
摘得人工智能“奥斯卡”的为何是它们,AI的未来会因它们而改变吗?