【问题标题】:Encoding/Escaping JSON Control Characters编码/转义 JSON 控制字符
【发布时间】:2017-08-17 14:55:53
【问题描述】:

我正在使用 MariaDB 的 COLUMN_JSON() 函数。正如this bug 说明的那样,该函数正确地转义了双引号,而不是应该编码/转义的其他字符。

这是一个愚蠢的示例查询,用于演示如何创建 JSON 列。

SELECT CONCAT('[', GROUP_CONCAT(COLUMN_JSON(COLUMN_CREATE(
        'name', `name`,
        'value', `value`
    )) SEPARATOR ','), ']') AS `json`
FROM `settings`

如果namevalue 包含无效的JSON 字符,json_decode 将失败。

我编写了一个 PHP 函数来转义/编码来自查询的值,但似乎应该有更好的方法。

/**
 * Makes sure the JSON values built by COLUMN_JSON() in MariaDB are safe for json_decode()
 * Assumes that double quotes are already escaped
 *
 * @param string $mysql_json
 * @return string
 */
public static function jsonEscape($mysql_json)
{
    $rtn = '';
    for ($i = 0; $i < strlen($mysql_json); ++$i) {
        $char = $mysql_json[$i];
        if (($char === '\\') && ($mysql_json[$i + 1] !== '"')) {
            // escape a backslash, but leave escaped double quotes intact
            $rtn .= '\\\\';
        } elseif (($ord = ord($char)) && ($ord < 32)) {
            // hex encode control characters (below ASCII 32)
            $rtn .= '\\u' . str_pad(dechex($ord), 4, '0', STR_PAD_LEFT);
        } else {
            $rtn .= $char;
        }
    }
    return $rtn;
}

像这样逐个字符地检查字符串效果不佳。也许有更高效的字符串替换或正则表达式?

【问题讨论】:

  • 我不认为这是一个错误。 Claudio Galdiolo 显示的问题是他的查看器没有逃避\n,问题不在Maria DB 中。换行符是\n\u000A,但肯定不是\\n
  • 如果值具有控制字符,PHP 的 json_decode() 将阻塞来自 MariaDB 的 COLUMN_JSON() 函数的值。我已经验证了该行为,并在寻找解决方案时发现了错误报告。
  • 让我们假设错误存在。试试看str_replacestrpos 的实现是否更快。请注意str_replace 接受value-&gt;replacements 的数组。对于 strpos,您需要循环播放所有 32 个字符。
  • @RyanVincent - 没有“原始字符串” - COLUMN_JSON() 正在使用数据库列中的值创建字符串。列中的值不是 JSON 安全的。它们包含引号、回车符等。
  • @RyanVincent - 重点。添加了示例查询。

标签: php mysql json mariadb


【解决方案1】:

根据Halcyon 的评论,我切换到str_replace() 解决方案,它的性能要好得多! trim(json_encode(13), '"')'\\u' . str_pad(dechex(13), 4, '0', STR_PAD_LEFT) 之间的性能差异只是稍微好一点,但它使意图更加清晰。

private static $json_replace_search;
private static $json_replace_replace;

/**
 * Makes sure the JSON values built by GROUP_CONCAT() and COLUMN_JSON() in MariaDB are safe for json_decode()
 * Assumes that double quotes are already escaped
 *
 * @param string $mysql_json
 * @return string
 */
public static function jsonEscape($mysql_json)
{
    if (is_null(self::$json_replace_search)) {
        // initialize
        self::$json_replace_search = [];
        self::$json_replace_replace = [];
        // set up all of the control characters (below ASCII 32)
        for ($i = 0; $i < 32; ++$i) {
            self::$json_replace_search[$i] = chr($i);
            self::$json_replace_replace[$i] = trim(json_encode(self::$json_replace_search[$i]), '"');
        }
    }
    // replace them
    return str_replace(self::$json_replace_search, self::$json_replace_replace, $mysql_json);
}

/**
 *
 * @param string $mysql_json
 * @return mixed
 */
public static function jsonDecode($mysql_json)
{
    return json_decode(self::jsonEscape($mysql_json));
}

【讨论】:

    猜你喜欢
    • 2014-05-31
    • 1970-01-01
    • 2019-12-06
    • 2013-09-08
    • 1970-01-01
    • 2010-11-06
    • 1970-01-01
    • 1970-01-01
    • 2019-12-10
    相关资源
    最近更新 更多