From 478227d9ace450de17c4aabc957739f99d6534f4 Mon Sep 17 00:00:00 2001 From: Paul Matthews Date: Fri, 20 Apr 2012 16:15:12 +0100 Subject: [PATCH] Fixed quoting issues with Yaml Inline Parser * Added test parse error in parseQuotedScalar * Expecting to throw tests, previously trimmed string * More details on issue: https://github.com/symfony/symfony/issues/4021 * Enforces single quote escaping when within string quotes * Shortens the scope of the validation match * Stricter matching rules * Ensures double quoted strings are not parsed incorrectly * Split quote matching into 2 types of quotes * Separates single and double quotes * Fixes intollerence for un escaped double quote --- src/Symfony/Component/Yaml/Inline.php | 13 +++++++- .../Component/Yaml/Tests/InlineTest.php | 31 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index 5933ac79c7..aa13ab35f1 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -21,6 +21,8 @@ use Symfony\Component\Yaml\Exception\DumpException; class Inline { const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\']*(?:\'\'[^\']*)*)\')'; + const REGEX_SINGLE_QUOTED_STRING = '(?:\'([^\']*(?:\'\'[^\']*)*)\')(?!.*\')'; + const REGEX_DOUBLE_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)")(?!.*")'; /** * Converts a YAML string to a PHP array. @@ -196,7 +198,16 @@ class Inline */ static private function parseQuotedScalar($scalar, &$i) { - if (!preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) { + // Only check the current item we're dealing with (for sequences) + $subject = substr($scalar, $i); + $items = preg_split('/[\'"]\s*(?:[,:]|[}\]]\s*,)/', $subject); + $subject = substr($subject, 0, strlen($items[0]) + 1); + + if (($scalar[$i] == "'" + && !preg_match('/'.self::REGEX_SINGLE_QUOTED_STRING.'/Au', $subject, $match)) + || ($scalar[$i] == '"' + && !preg_match('/'.self::REGEX_DOUBLE_QUOTED_STRING.'/Au', $subject, $match)) + ) { throw new ParseException(sprintf('Malformed inline YAML string (%s).', substr($scalar, $i))); } diff --git a/src/Symfony/Component/Yaml/Tests/InlineTest.php b/src/Symfony/Component/Yaml/Tests/InlineTest.php index f22b9fa133..e33556df11 100644 --- a/src/Symfony/Component/Yaml/Tests/InlineTest.php +++ b/src/Symfony/Component/Yaml/Tests/InlineTest.php @@ -65,6 +65,34 @@ class InlineTest extends \PHPUnit_Framework_TestCase $this->assertSame($value, Inline::parse(Inline::dump($value))); } + /** + * + * @expectedException \Symfony\Component\Yaml\Exception\ParseException + */ + public function testParseScalarWithIncorrectlyQuotedStringShouldThrowException() + { + $value = "'don't do somthin' like that'"; + Inline::parseScalar($value); + } + + /** + * + * @expectedException \Symfony\Component\Yaml\Exception\ParseException + */ + public function testParseScalarWithIncorrectlyDoubleQuotedStringShouldThrowException() + { + $value = '"don"t do somthin" like that"'; + Inline::parseScalar($value); + } + + public function testParseScalarWithCorrectlyQuotedStringShouldReturnString() + { + $value = "'don''t do somthin'' like that'"; + $expect = "don't do somthin' like that"; + + $this->assertSame($expect, Inline::parseScalar($value)); + } + protected function getTestsForParse() { return array( @@ -124,6 +152,7 @@ class InlineTest extends \PHPUnit_Framework_TestCase '[foo, {bar: foo, foo: [foo, {bar: foo}]}, [foo, {bar: foo}]]' => array('foo', array('bar' => 'foo', 'foo' => array('foo', array('bar' => 'foo'))), array('foo', array('bar' => 'foo'))), '[foo, bar: { foo: bar }]' => array('foo', '1' => array('bar' => array('foo' => 'bar'))), + '[foo, \'@foo.baz\', { \'%foo%\': \'foo is %foo%\', bar: \'%foo%\' }, true, \'@service_container\']' => array('foo', '@foo.baz', array('%foo%' => 'foo is %foo%', 'bar' => '%foo%',), true, '@service_container',), ); } @@ -167,6 +196,8 @@ class InlineTest extends \PHPUnit_Framework_TestCase '[foo, { bar: foo }]' => array('foo', array('bar' => 'foo')), '[foo, { bar: foo, foo: [foo, { bar: foo }] }, [foo, { bar: foo }]]' => array('foo', array('bar' => 'foo', 'foo' => array('foo', array('bar' => 'foo'))), array('foo', array('bar' => 'foo'))), + + '[foo, \'@foo.baz\', { \'%foo%\': \'foo is %foo%\', bar: \'%foo%\' }, true, \'@service_container\']' => array('foo', '@foo.baz', array('%foo%' => 'foo is %foo%', 'bar' => '%foo%',), true, '@service_container',), ); } }