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

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

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

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

转换为:

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

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

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

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

【问题讨论】:

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

标签: php mysql quotes smart-quotes


【解决方案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 之前需要原始数据,则在制作转义版本时不要删除原始数据。
    • 这是因为我有一个函数可以递归地添加/删除斜杠(参见stackoverflow.com/questions/1216552/…)。这个想法是在提交后将所有表单数据带到一致的状态,例如删除魔术引号,必要时处理数据,然后将它们添加回 MySQL 查询。不过我想我很快就会切换到参数化查询,这样可以省去很多麻烦!
    • 啊,好吧。 IMO 对魔术引号唯一有价值的事情是删除它们,因此您只需要 stripslashes() 即可。 :)
    猜你喜欢
    • 2013-05-25
    • 1970-01-01
    • 1970-01-01
    • 2011-02-11
    • 2016-03-11
    • 1970-01-01
    • 1970-01-01
    • 2011-02-19
    • 2020-10-15
    相关资源
    最近更新 更多