Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions spyc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ morelesskey: "<value>"

array_of_zero: [0]
sophisticated_array_of_zero: {rx: {tx: [0]} }
key_value_str_json_map: {"rx": {"tx": ["fx", "sx"]}, "ab": {"cd":"de"} }
key_value_str_json_list: [{"rx": {"tx": ["fx", "sx"]}}, {"ab": {"cd":"de"}}]

switches:
- { row: 0, col: 0, func: {tx: [0, 1]} }
Expand Down
15 changes: 13 additions & 2 deletions src/Spyc.php
Original file line number Diff line number Diff line change
Expand Up @@ -1063,10 +1063,21 @@ private function returnKeyValuePair ($line) {
$key = trim(array_shift($explode));
$value = trim(implode(': ', $explode));
$this->checkKeysInValue($value);
// Other methods currently don't parse valid json maps or arrays of maps correctly
if ( str_starts_with( $value, '[{' ) || str_starts_with( $value, '{"' ) ) {
$decoded = json_decode( preg_replace( '/^.*?:\s*/', '', $line ), true );
if ($decoded !== null || (json_last_error() === JSON_ERROR_NONE && $decoded === null)) {
// Accept null as valid JSON value, but only if no error occurred
$value = $decoded;
}
// Otherwise, leave $value as-is (fallback to original string)
}
Comment on lines +1067 to +1074

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

This is a good fix for handling JSON values. However, the current implementation has a few issues that should be addressed:

  1. PHP Compatibility (critical): The use of str_starts_with() was introduced in PHP 8.0. Using it will break backward compatibility for projects running on older PHP versions, which this library appears to support.
  2. Redundant Parsing (high): The code uses preg_replace('/^.*?:\s*/', '', $line) to re-extract the value from the line. This is unnecessary and less efficient, as the value has already been correctly parsed into the $value variable.
  3. Brittle JSON Detection (medium): The condition to detect a JSON string is too specific. It will fail for valid JSON with leading whitespace (e.g., { "key": "value" }) or other valid JSON structures.

I've provided a suggestion below that resolves all these points by using a more robust and backward-compatible approach.

        // The default inline parser (_toType) does not correctly handle complex JSON objects.
        // Attempt to parse as JSON first for values that look like potential JSON.
        $first_char = isset($value[0]) ? $value[0] : '';
        if ($first_char === '{' || $first_char === '[') {
          $decoded = json_decode($value, true);
          // If the value is valid JSON, use the decoded array.
          // This correctly handles valid JSON 'null' as well.
          if (json_last_error() === JSON_ERROR_NONE) {
            $value = $decoded;
          }
          // Otherwise, leave $value as a string for the legacy parser to handle.
        }

}
// Set the type of the value. Int, string, etc
$value = $this->_toType($value);
if ($key === '0') $key = '__!YAMLZero';
if ( ! is_array( $value ) ) {
$value = $this->_toType($value);
if ($key === '0') $key = '__!YAMLZero';
}
$array[$key] = $value;
} else {
$array = array ($line);
Expand Down