【问题标题】:PHP MySQLi Prepared Statements trimming strings with "non-standard" characters?PHP MySQLi Prepared Statements用“非标准”字符修剪字符串?
【发布时间】:2014-02-21 23:30:39
【问题描述】:

我遇到了一个奇怪的问题,我以前从未遇到过准备好的语句。我正在使用内置的 PHP MySQLi 函数将数据插入数据库。

代码如下所示:

$mysqli = new mysqli("localhost", "user", "pass", "test");
$mysqli->set_charset('utf8');
$stmt = $mysqli->prepare("INSERT INTO `lines` (`description`) VALUES (?)");
$stmt->bind_param("s", $_POST['description']);
$stmt->execute();

在名为“description”的文本区域中,输入以下字符串:

爱丽丝喜欢鲍勃的猫。

请注意,撇号不是常规的 ' 类型,而是我从电子邮件中复制该行(在 OS X 的邮件应用程序中)得到的。

当文本区域作为表单的一部分提交时,存储在表中的字段中的值为:

爱丽丝喜欢鲍勃

其余的被切断。我已经尽我所能进行了调试,并且我知道以下内容是正确的:

  1. $_POST['description'] 变量的值在放入 bind_param 函数之前是正确的。
  2. 数据库表应该使用 UTF8(我尝试了 utf8_bin 和 utf8_unicode_ci 的排序规则,但似乎都不起作用)。
  3. 当我使用 phpMyAdmin 之类的工具输入相同的字符串时,它可以工作。

我最初认为这是一个编码问题,但第 (3) 点似乎与此相矛盾,所以我唯一剩下的就是我设置语句的方式有问题。

如果有人能提供一些启示,那将是最有帮助的。

【问题讨论】:

  • 你的问题中没有证据可以让你责怪mysqli。只要您未能发布可以证明 mysqli 准备语句中存在错误的可重现测试用例,就可以使用这些标签标记您的问题。
  • 我将问题标记为 MySQLi,因为它涉及 MySQLi。我从来没有说过这是 MySQLi 的错误,但是这个站点上有些人使用 MySQLi,并且可能以前遇到过它。也没有证据表明我的问题属于“HTML”领域,您一直坚持用它来标记它。这不是 HTML 问题。
  • 嗯,这似乎是一个编码问题。检查源字符串的编码,然后相应地更改 SET NAMES 参数

标签: php mysqli prepared-statement


【解决方案1】:

所以事实证明它与我最初怀疑的编码相关。 this question 中的最佳答案解决了这个问题,但是我仍然无法解释为什么不是只错误地显示字符(或不正确地存储它),而是在那个时候截断了字符串。如果有人对为什么会发生这种情况有实际的答案,如果只是出于学术原因,将不胜感激!

【讨论】:

  • 您应该在 3 个区域使用相同的编码:PHP、MySQL 连接和 MySQL 表。您可以通过运行 SET NAMES 来设置连接的编码。智能引号可能超出您使用的有效字符集。
【解决方案2】:

你需要在插入前转义你的字符串

<?php
$str = "Is your name O'reilly?";

// Outputs: Is your name O\'reilly?
echo addslashes($str);
?>

示例取自 PHP 文档。

您可能还需要考虑安全性 - 将帖子数据插入 SQL 而不进行验证绝不是一个好主意。

【讨论】:

  • 你怎么知道他没有验证?他不需要逃跑,因为他使用准备好的陈述
  • 我的代码清楚地使用了准备好的语句,我的问题标题也提到了这一点。因此,“转义”是不必要的。
  • Prepared statements 保护 aginst SQL injection - 同意 - 但还有许多其他问题,例如可能值得考虑的 Javascript 注入 - 只是一个建议。关于字符集 - 似乎没有存储格式错误的字符 - 看起来单引号已经终止了字符串 - 因为它后面什么都没有出现。
  • 我已经处理了 JavaScript 注入,并且仅当您从数据库中输出值而不是将它们插入其中时才会发生这种情况。对您的答案的编辑也无济于事,因为我正在使用准备好的陈述。如果我先转义值,转义的字符串(带有反斜杠)将作为实际值存储在数据库中,这不是我想要的。
  • 安全辩论让我们偏离主题 - 关于转义 - 如果值终止字符串,您需要转义/修改它 - 不是为了存储 - 而是确保 PHP 将其视为数据而不是将其作为终止字符串的标记处理。
猜你喜欢
  • 2016-05-12
  • 2014-04-26
  • 1970-01-01
  • 2013-08-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多