Json::encode(): auto-sanitize bad UTF-8 strings

refs #2635
This commit is contained in:
Alexander A. Klimov 2018-04-27 17:15:54 +02:00
parent 1a841170ff
commit 9219cea776
1 changed files with 66 additions and 3 deletions

View File

@ -28,10 +28,17 @@ class Json
} else {
$encoded = json_encode($value, $options, $depth);
}
if (json_last_error() !== JSON_ERROR_NONE) {
throw new JsonEncodeException('%s: %s', static::lastErrorMsg(), var_export($value, true));
switch (json_last_error()) {
case JSON_ERROR_NONE:
return $encoded;
case JSON_ERROR_UTF8:
return static::encode(static::sanitizeUtf8Recursive($value), $options, $depth);
default:
throw new JsonEncodeException('%s: %s', static::lastErrorMsg(), var_export($value, true));
}
return $encoded;
}
/**
@ -82,4 +89,60 @@ class Json
return 'Unknown error';
}
}
/**
* Replace bad byte sequences in UTF-8 strings inside the given JSON-encodable structure with question marks
*
* @param mixed $value
*
* @return mixed
*/
protected static function sanitizeUtf8Recursive($value)
{
switch (gettype($value)) {
case 'string':
return static::sanitizeUtf8String($value);
case 'array':
$sanitized = array();
foreach ($value as $key => $val) {
if (is_string($key)) {
$key = static::sanitizeUtf8String($key);
}
$sanitized[$key] = static::sanitizeUtf8Recursive($val);
}
return $sanitized;
case 'object':
$sanitized = array();
foreach ($value as $key => $val) {
if (is_string($key)) {
$key = static::sanitizeUtf8String($key);
}
$sanitized[$key] = static::sanitizeUtf8Recursive($val);
}
return (object) $sanitized;
default:
return $value;
}
}
/**
* Replace bad byte sequences in the given UTF-8 string with question marks
*
* @param string $string
*
* @return string
*/
protected static function sanitizeUtf8String($string)
{
return mb_convert_encoding($string, 'UTF-8', 'UTF-8');
}
}