Php 编码/转义JSON控制字符
我正在使用MariaDB的函数。如图所示,该函数正确地转义双引号,但不转义其他应编码/转义的字符 下面是一个愚蠢的查询示例,演示如何创建JSON列Php 编码/转义JSON控制字符,php,mysql,json,mariadb,Php,Mysql,Json,Mariadb,我正在使用MariaDB的函数。如图所示,该函数正确地转义双引号,但不转义其他应编码/转义的字符 下面是一个愚蠢的查询示例,演示如何创建JSON列 SELECT CONCAT('[', GROUP_CONCAT(COLUMN_JSON(COLUMN_CREATE( 'name', `name`, 'value', `value` )) SEPARATOR ','), ']') AS `json` FROM `settings` 如果名称或值包含无效的JS
SELECT CONCAT('[', GROUP_CONCAT(COLUMN_JSON(COLUMN_CREATE(
'name', `name`,
'value', `value`
)) SEPARATOR ','), ']') AS `json`
FROM `settings`
如果名称
或值
包含无效的JSON字符,JSON\u解码
将失败
我已经编写了一个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;
}
/**
*确保MariaDB中列_JSON()生成的JSON值对于JSON_decode()是安全的
*假设双引号已经转义
*
*@param string$mysql\u json
*@返回字符串
*/
公共静态函数jsonEscape($mysql\u json)
{
$rtn='';
对于($i=0;$i
像这样逐个字符检查字符串性能不好。也许有一个字符串替换或正则表达式性能更好?根据的一条评论,我切换到了stru 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));
}
private static$json\u replace\u search;
私有静态$json\u replace\u replace;
/**
*确保MariaDB中的组_CONCAT()和列_JSON()生成的JSON值对于JSON_decode()是安全的
*假设双引号已经转义
*
*@param string$mysql\u json
*@返回字符串
*/
公共静态函数jsonEscape($mysql\u json)
{
if(为null(self:$json\u replace\u search)){
//初始化
self::$json_replace_search=[];
self::$json_replace_replace=[];
//设置所有控制字符(低于ASCII 32)
对于($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]),“”);
}
}
//替换它们
返回str_replace(self:$json_replace_search,self:$json_replace_replace,$mysql_json);
}
/**
*
*@param string$mysql\u json
*@返回混合
*/
公共静态函数jsonDecode($mysql\u json)
{
返回json_decode(self::jsonEscape($mysql_json));
}
我不认为这是一个bug。正如Claudio Galdiolo所显示的问题是他的观众没有逃过\n
,问题不在Maria DB中。换行符不是\n
就是\u000A
,但肯定不是\\n
。PHP的json\u decode()
会被MariaDB的列的值阻塞()
函数,如果值具有控制字符。我已经验证了行为,并在寻找解决方案时找到了错误报告。让我们假设错误存在。尝试看看str\u replace
或strpos
实现是否更快。请注意str\u replace
接受一个value->replaces
数组或strpos您需要循环所有32个字符。@RyanVincent-没有“原始字符串”-COLUMN_JSON()正在使用数据库列中的值创建字符串。该列中的值不是JSON安全的。它们包含引号、回车等。@RyanVincent-突出点。添加了查询示例。