diff --git a/Changelog.txt b/Changelog.txt index 2e35abf..f0c08e6 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -12,7 +12,14 @@ found at: === Changes made since last versioned release === - [2023.12.01; Maikuolan]: Improved escaping. Added support for specifying a - Redis database number to the cache handler. + Redis database number to the cache handler (CIDRAM/CIDRAM#540). + +- [2023.12.08; Bug-fix; Maikuolan]: Not escaping keys when reconstructing YAML + data could prevent successful reprocessing of those keys if said keys + contained any hashes or backslashes. The solution is to enforce escaping of + keys when such bytes are detected, regardless of how the property for quoting + keys is defined. Accordingly, that's been done, and a new method added for + that purpose (CIDRAM/CIDRAM#547). === Version/Release 1.10.0 === MINOR RELEASE. diff --git a/src/YAML.php b/src/YAML.php index 22d2e2c..648801b 100644 --- a/src/YAML.php +++ b/src/YAML.php @@ -1,6 +1,6 @@ QuoteKeys ? $this->scalarToString($Key) : $Key) . ':'; + $Out .= ($this->QuoteKeys ? $this->scalarToString($Key) : $this->escapeKey($Key)) . ':'; } if (is_array($Value)) { $this->processInner($Value, $Out, $Depth + 1); @@ -795,9 +795,9 @@ private function processInner(array $Arr, &$Out, $Depth = 0) $ThisDepth = str_repeat($this->Indent, $Depth); if ($NullSet && !$Sequential) { $Out .= $ThisDepth . '?'; - $Value = $Key; + $Value = $this->escapeKey($Key); } else { - $Out .= $ThisDepth . ($Sequential ? '-' : ($this->QuoteKeys ? $this->scalarToString($Key) : $Key) . ':'); + $Out .= $ThisDepth . ($Sequential ? '-' : ($this->QuoteKeys ? $this->scalarToString($Key) : $this->escapeKey($Key)) . ':'); } if (is_array($Value)) { if ($Depth < $this->FlowRebuildDepth - 1) { @@ -855,10 +855,10 @@ private function processInner(array $Arr, &$Out, $Depth = 0) private function escape($Value = '', $Newlines = true) { if ($this->Quotes === "'") { - return str_replace("'", "''", $Value); + return str_replace(['\\', '#', "'"], ['\\\\', '\#', "''"], $Value); } if ($this->Quotes !== '"') { - return $Value; + return str_replace(['\\', '#'], ['\\\\', '\#'], $Value); } $Value = str_replace('\\', '\\\\', $Value); if ($Newlines) { @@ -891,6 +891,23 @@ private function escape($Value = '', $Newlines = true) return $Value; } + /** + * Escape keys if necessary (or else there could be problems with hashes). + * + * @param string $Key The key to escape. + * @return string The escaped key. + */ + private function escapeKey($Key = '') + { + if (!is_string($Key)) { + return ''; + } + if (strpos($Key, '#') === false && strpos($Key, '\\') === false) { + return $Key; + } + return '"' . str_replace(['\\', '#'], ['\\\\', '\#'], $Key) . '"'; + } + /** * Unescape according to the YAML specification. * @@ -944,9 +961,9 @@ private function unescape($Value = '', $Style = '"') return $Value; } if ($Style === "'" || $Style === "\xe2\x80\x98" || $Style === "\x93") { - return str_replace("''", "'", $Value); + return str_replace(["''", '\#', '\\\\'], ["'", '#', '\\'], $Value); } - return $Value; + return str_replace(['\#', '\\\\'], ['#', '\\'], $Value); } /**