【问题标题】:Strange string comparison results after retrieving TEXT value检索 TEXT 值后的奇怪字符串比较结果
【发布时间】:2012-03-09 21:22:26
【问题描述】:

我正在从多个页面中抓取数据并插入到我的 MySQL 数据库中。可能有重复;我只想存储唯一的条目。以防我的主键不够用,我进行了一个测试,当我收到 MySQL 1062 错误*(主键上的重复条目**)时会检查该测试。该测试检查要插入的元组的所有片段是否与存储的元组相同。我发现当我收到 1062 错误时,存储的元组和抓取的元组仅相差一个元素/字段,即 TEXT 字段。

首先,我检索了已经存储的条目并将它们都传递给htmlspecialchars(),以直观地比较输出;它们看起来一模一样。

根据strlen(),从数据库中检索到的字符串长度为 304 个字符,但新抓取的字符串为 305。similar_text() 通过返回 304*** 支持这一点。

然后我循环遍历一个字符串,将一个字符与另一个字符串进行比较,当出现不匹配时停止。问题是第一个字符。在来自数据库的字符串中,它是N,但两个字符串似乎都以I 开头(即使在它们来自htmlspecialchars() 的输出中也是如此)。另外,DB 字符串应该是短了一个字符,而不是长了。

然后我再次检查了输出(打印htmlspecialchars())和strlen(),但这一次是在插入原始字符串(最终在数据库中的字符串)之前和插入重复字符串之前。它们看起来和以前一样,strlen() 都返回 305。

所以这让我觉得它们一定是我的 PHP 和我的 MySQL 之间发生的事情。因此,我没有将新刮取的字符串与数据库中具有相同主键(ID)的字符串进行比较,而是尝试检索一个元组,其中每个字段都等于新刮取部分中它们各自的部分,如SELECT * FROM table WHERE value1='{$MYSQL_ESCAPED['value1']}' .... AND valueN='{$MYSQL_ESCAPED['valueN']}'; 和返回元组。因此,它们在各个方面都是相同的,包括有问题的 TEXT 字段。

这是怎么回事?

当我在字符串前面看到N 时,我立刻想到了来自 MSSQL 的NVARCHAR 等,但据我所知,这不是 MySQL 的一部分,但是...

这和"Each TEXT value is stored using a two-byte length prefix that indicates the number of bytes in the value."这个事实有什么关系吗?

或者这只是指向字符编码问题?


编辑:

  • 数据库中没有存储多字节字符。
  • mb_strlen() 返回与上述strlen() 相同的结果。
  • 在插入数据库之前使用utf8_encode()mb_convert_encoding() 没有区别;一个不可见的N 仍然作为从数据库中检索到的字符串的前缀。

注意事项

  • 在将任何字符串插入我的数据库之前,我将其传递给mysql_real_escape_string(trim(preg_replace('/\s\s+/', ' ', $str))),它将双空格替换为单空格,删除前导和尾随空格并将其转义以供 MySQL 插入。
  • 我打印输出和测试的页面是 UTF-8。
  • 创建后,我的 DB 将其字符集设置为 utf8,将其排序规则设置为 utf8_general_ci,并且我也使用了 SET NAMES 'utf8' COLLATE 'utf8_general_ci'; 命令,以防万一。
  • 脚注:
    • *然后我也强制退出爬取。
    • ** 主键只是我从页面中抓取的 ID (VARCHAR(10))。
    • ***常用字符数

【问题讨论】:

  • 使用base64_encode()给我们二进制安全字符串,一个前后db问题。
  • @chris Base64 编码版本的抓取(重复)字符串:SW50ZXJwZXJzb25hbCBjb21tdW5pY2F0aW9uOyBDb21tdW5pY2F0aW9uIGluIGdyb3VwcyBhbmQgdGVhbXMuIExlYWRlcnNoaXAgYW5kIG1vdGl2YXRpb24gYXMgY3JpdGljYWwgZmFjdG9ycyBpbiB0aGUgbWFuYWdlbWVudCBvZiBlZmZlY3RpdmUgY29tbXVuaWNhdGlvbi4gIFRoZSBlc3NlbnRpYWwgY29tcG9uZW50cyBvZiBlZmZlY3RpdmUgcmVwb3J0IHdyaXRpbmcgYW5kIGVuaGFuY2UgcHJlc2VudGF0aW9uIHNraWxscy4gQ29tbXVuaWNhdGlvbiBza2lsbHMgYXMgYW4gZWZmZWN0aXZlIHRvb2wgZm9yIG1hbmFnaW5nIGNoYW5nZS4=.
  • @chris Base64 编码的原始字符串版本(从数据库中检索后):SW50ZXJwZXJzb25hbCBjb21tdW5pY2F0aW9uOyBDb21tdW5pY2F0aW9uIGluIGdyb3VwcyBhbmQgdGVhbXMuIExlYWRlcnNoaXAgYW5kIG1vdGl2YXRpb24gYXMgY3JpdGljYWwgZmFjdG9ycyBpbiB0aGUgbWFuYWdlbWVudCBvZiBlZmZlY3RpdmUgY29tbXVuaWNhdGlvbi4gVGhlIGVzc2VudGlhbCBjb21wb25lbnRzIG9mIGVmZmVjdGl2ZSByZXBvcnQgd3JpdGluZyBhbmQgZW5oYW5jZSBwcmVzZW50YXRpb24gc2tpbGxzLiBDb21tdW5pY2F0aW9uIHNraWxscyBhcyBhbiBlZmZlY3RpdmUgdG9vbCBmb3IgbWFuYWdpbmcgY2hhbmdlLg==
  • @chris 在进入数据库之前,两个字符串(经过 Base64 编码)都等于SW50ZXJwZXJzb25hbCBjb21tdW5pY2F0aW9uOyBDb21tdW5pY2F0aW9uIGluIGdyb3VwcyBhbmQgdGV‌​hbXMuIExlYWRlcnNoaXAgYW5kIG1vdGl2YXRpb24gYXMgY3JpdGljYWwgZmFjdG9ycyBpbiB0aGUgbWFu‌​YWdlbWVudCBvZiBlZmZlY3RpdmUgY29tbXVuaWNhdGlvbi4gIFRoZSBlc3NlbnRpYWwgY29tcG9uZW50c‌​yBvZiBlZmZlY3RpdmUgcmVwb3J0IHdyaXRpbmcgYW5kIGVuaGFuY2UgcHJlc2VudGF0aW9uIHNraWxscy‌​4gQ29tbXVuaWNhdGlvbiBza2lsbHMgYXMgYW4gZWZmZWN0aXZlIHRvb2wgZm9yIG1hbmFnaW5nIGNoYW5‌​nZS4=

标签: php mysql encoding character-encoding string-comparison


【解决方案1】:

TEXT 字段会在 MySQL 认为合适时进行字符集转换。但是,MySQL 不会无缘无故地随机添加/删除数据。虽然文本字段确实将数据的长度存储为包含文本字段数据的磁盘数据 blob 头部的 2 个额外字节,但这 2 个字节永远不会暴露给最终用户。假设字符集设置在整个客户端->数据库->磁盘上->数据库->客户端管道中都是相同的,那么任何地方的字符串长度都不应该发生变化。

【讨论】:

    猜你喜欢
    • 2019-10-26
    • 1970-01-01
    • 1970-01-01
    • 2011-09-18
    • 2011-04-07
    • 1970-01-01
    • 1970-01-01
    • 2011-05-06
    • 1970-01-01
    相关资源
    最近更新 更多