2017-03-24 6 views
0

Ich verwende MariaDB COLUMN_JSON() Funktion. Wie this bug zeigt, entkoppelt die Funktion richtig doppelte Anführungszeichen, aber nicht andere Zeichen, die codiert werden sollen.Codierung/Escaping JSON-Steuerzeichen

Hier ist eine alberne Beispielabfrage, um zu demonstrieren, wie die JSON-Spalte erstellt wird.

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

Wenn die name oder value ungültige JSON Zeichen enthalten, werden json_decode scheitern.

Ich habe eine PHP-Funktion geschrieben, um den Wert, der von der Abfrage kommt, zu entschlüsseln/zu kodieren, aber es scheint, als sollte es einen besseren Weg geben.

/** 
* 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; 
} 

Untersuchen Sie die Zeichenfolge Zeichen für Zeichen, wie dies nicht gut funktioniert. Vielleicht gibt es einen String-Ersatz oder einen regulären Ausdruck, der performanter wäre?

+0

Ich glaube nicht, dass dies ein Fehler ist. Das Problem als _Claudio Galdiolo_ zeigt, dass sein Betrachter nicht dem '\ n' entkommt, das Problem liegt nicht in Maria DB. Ein Newline ist entweder '\ n' oder' \ u000A', aber sicher nicht '\\ n'. – Halcyon

+0

PHP '' json_decode() 'wird auf Werte ersticken, die aus MariaDB' COLUMN_JSON() 'Funktion kommen, wenn die Werte Steuerzeichen haben. Ich habe das Verhalten überprüft und den Fehlerbericht gefunden, als ich nach einer Lösung suchte. – Sonny

+1

Nehmen wir an, der Fehler ist da. Versuchen Sie zu sehen, ob 'str_replace' oder eine 'strpos'-Implementierung schneller ist. Beachten Sie, dass 'str_replace' ein Array von' value-> replacements' akzeptiert. Für Strop müssen Sie alle 32 Zeichen durchlaufen. – Halcyon

Antwort

0

Basierend auf einem Kommentar von Halcyon, wechselte ich zu einer str_replace() Lösung, und es funktioniert viel besser! Der Leistungsunterschied zwischen trim(json_encode(13), '"') und '\\u' . str_pad(dechex(13), 4, '0', STR_PAD_LEFT) ist gerade kaum besser, aber es macht die Absicht klarer.

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)); 
}