diff --git a/externals/jsonlint/src/Seld/JsonLint/JsonParser.php b/externals/jsonlint/src/Seld/JsonLint/JsonParser.php --- a/externals/jsonlint/src/Seld/JsonLint/JsonParser.php +++ b/externals/jsonlint/src/Seld/JsonLint/JsonParser.php @@ -380,11 +380,7 @@ $errStr .= "Duplicate key: ".$tokens[$len][0]; throw new JsonLintParsingException($errStr); } elseif (($this->flags & self::ALLOW_DUPLICATE_KEYS) && array_key_exists($key, $tokens[$len-2])) { - $duplicateCount = 1; - do { - $duplicateKey = $key . '.' . $duplicateCount++; - } while (array_key_exists($duplicateKey, $tokens[$len-2])); - $key = $duplicateKey; + // Forget about it... } $yyval->token[$key] = $tokens[$len][1]; break; diff --git a/src/parser/PhutilJSONParser.php b/src/parser/PhutilJSONParser.php --- a/src/parser/PhutilJSONParser.php +++ b/src/parser/PhutilJSONParser.php @@ -8,6 +8,13 @@ */ final class PhutilJSONParser { + private $allowDuplicateKeys = false; + + public function setAllowDuplicateKeys($allow_duplicate_keys) { + $this->allowDuplicateKeys = $allow_duplicate_keys; + return $this; + } + public function parse($json) { $jsonlint_root = phutil_get_library_root('phutil').'/../externals/jsonlint'; require_once($jsonlint_root.'/src/Seld/JsonLint/JsonParser.php'); @@ -17,17 +24,17 @@ $parser = new JsonLintJsonParser(); try { - $output = $parser->parse($json); + $output = $parser->parse($json, $this->getFlags()); } catch (JsonLintParsingException $ex) { $details = $ex->getDetails(); $message = preg_replace("/^Parse error .*\\^\n/s", '', $ex->getMessage()); throw new PhutilJSONParserException( $message, - $details['loc']['last_line'], - $details['loc']['last_column'], - $details['token'], - $details['expected']); + idx(idx($details, 'loc', array()), 'last_line'), + idx(idx($details, 'loc', array()), 'last_column'), + idx($details, 'token'), + idx($details, 'expected')); } if (!is_array($output)) { @@ -40,4 +47,16 @@ return $output; } + private function getFlags() { + $flags = 0; + + if ($this->allowDuplicateKeys) { + $flags |= JsonLintJsonParser::ALLOW_DUPLICATE_KEYS; + } else { + $flags |= JsonLintJsonParser::DETECT_KEY_CONFLICTS; + } + + return $flags; + } + } diff --git a/src/parser/__tests__/PhutilJSONParserTestCase.php b/src/parser/__tests__/PhutilJSONParserTestCase.php --- a/src/parser/__tests__/PhutilJSONParserTestCase.php +++ b/src/parser/__tests__/PhutilJSONParserTestCase.php @@ -86,4 +86,29 @@ } } + public function testDuplicateKeys() { + $parser = new PhutilJSONParser(); + + $tests = array( + '{"foo": "bar", "foo": "baz"}' => array('foo' => 'baz'), + ); + + foreach ($tests as $input => $expect) { + $parser->setAllowDuplicateKeys(true); + $this->assertEqual( + $expect, + $parser->parse($input), + 'Parsing JSON: '.$input); + + $parser->setAllowDuplicateKeys(false); + $caught = null; + try { + $parser->parse($input); + } catch (Exception $ex) { + $caught = $ex; + } + $this->assertTrue($caught instanceof PhutilJSONParserException); + } + } + }