Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit c74f1aa

Browse filesBrowse files
committed
feature #17863 [Yaml] add support for parsing the !!binary tag (xabbuh)
This PR was merged into the 3.1-dev branch. Discussion ---------- [Yaml] add support for parsing the !!binary tag | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #8094, #15587, #17599 | License | MIT | Doc PR | TODO Commits ------- 79a63d5 [Yaml] add support for the !!binary tag
2 parents a0fd637 + 79a63d5 commit c74f1aa
Copy full SHA for c74f1aa

File tree

8 files changed

+181
-2
lines changed
Filter options

8 files changed

+181
-2
lines changed

‎src/Symfony/Component/Yaml/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Yaml/CHANGELOG.md
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ CHANGELOG
44
3.1.0
55
-----
66

7+
* Added support for parsing base64 encoded binary data when they are tagged
8+
with the `!!binary` tag.
9+
10+
* Added support for dumping binary data as base64 encoded strings by passing
11+
the `Yaml::DUMP_BASE64_BINARY_DATA` flag.
12+
713
* Added support for parsing timestamps as `\DateTime` objects:
814

915
```php

‎src/Symfony/Component/Yaml/Inline.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Yaml/Inline.php
+31Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,8 @@ public static function dump($value, $flags = 0)
197197
return $repr;
198198
case '' == $value:
199199
return "''";
200+
case Yaml::DUMP_BASE64_BINARY_DATA & $flags && self::isBinaryString($value):
201+
return '!!binary '.base64_encode($value);
200202
case Escaper::requiresDoubleQuoting($value):
201203
return Escaper::escapeWithDoubleQuotes($value);
202204
case Escaper::requiresSingleQuoting($value):
@@ -576,6 +578,8 @@ private static function evaluateScalar($scalar, $flags, $references = array())
576578
return -log(0);
577579
case '-.inf' === $scalarLower:
578580
return log(0);
581+
case 0 === strpos($scalar, '!!binary '):
582+
return self::evaluateBinaryScalar(substr($scalar, 9));
579583
case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar):
580584
return (float) str_replace(',', '', $scalar);
581585
case preg_match(self::getTimestampRegex(), $scalar):
@@ -595,6 +599,33 @@ private static function evaluateScalar($scalar, $flags, $references = array())
595599
}
596600
}
597601

602+
/**
603+
* @param string $scalar
604+
*
605+
* @return string
606+
*
607+
* @internal
608+
*/
609+
public static function evaluateBinaryScalar($scalar)
610+
{
611+
$parsedBinaryData = self::parseScalar(preg_replace('/\s/', '', $scalar));
612+
613+
if (0 !== (strlen($parsedBinaryData) % 4)) {
614+
throw new ParseException(sprintf('The normalized base64 encoded data (data without whitespace characters) length must be a multiple of four (%d bytes given).', strlen($parsedBinaryData)));
615+
}
616+
617+
if (!preg_match('#^[A-Z0-9+/]+={0,2}$#i', $parsedBinaryData)) {
618+
throw new ParseException(sprintf('The base64 encoded data (%s) contains invalid characters.', $parsedBinaryData));
619+
}
620+
621+
return base64_decode($parsedBinaryData, true);
622+
}
623+
624+
private static function isBinaryString($value)
625+
{
626+
return preg_match('/[^\x09-\x0d\x20-\xff]/', $value);
627+
}
628+
598629
/**
599630
* Gets a regex that matches a YAML date.
600631
*

‎src/Symfony/Component/Yaml/Parser.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Yaml/Parser.php
+9-2Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
*/
2121
class Parser
2222
{
23+
const TAG_PATTERN = '((?P<tag>![\w!.\/:-]+) +)?';
2324
const BLOCK_SCALAR_HEADER_PATTERN = '(?P<separator>\||>)(?P<modifiers>\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P<comments> +#.*)?';
2425

2526
private $offset = 0;
@@ -516,10 +517,16 @@ private function parseValue($value, $flags, $context)
516517
return $this->refs[$value];
517518
}
518519

519-
if (preg_match('/^'.self::BLOCK_SCALAR_HEADER_PATTERN.'$/', $value, $matches)) {
520+
if (preg_match('/^'.self::TAG_PATTERN.self::BLOCK_SCALAR_HEADER_PATTERN.'$/', $value, $matches)) {
520521
$modifiers = isset($matches['modifiers']) ? $matches['modifiers'] : '';
521522

522-
return $this->parseBlockScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), (int) abs($modifiers));
523+
$data = $this->parseBlockScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), (int) abs($modifiers));
524+
525+
if (isset($matches['tag']) && '!!binary' === $matches['tag']) {
526+
return Inline::evaluateBinaryScalar($data);
527+
}
528+
529+
return $data;
523530
}
524531

525532
try {

‎src/Symfony/Component/Yaml/Tests/DumperTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Yaml/Tests/DumperTest.php
+16Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,22 @@ public function getEscapeSequences()
276276
'paragraph-separator' => array("\t\\P", '"\t\\\\P"'),
277277
);
278278
}
279+
280+
public function testBinaryDataIsDumpedAsIsWithoutFlag()
281+
{
282+
$binaryData = file_get_contents(__DIR__.'/Fixtures/arrow.gif');
283+
$expected = "{ data: '".str_replace("'", "''", $binaryData)."' }";
284+
285+
$this->assertSame($expected, $this->dumper->dump(array('data' => $binaryData)));
286+
}
287+
288+
public function testBinaryDataIsDumpedBase64EncodedWithFlag()
289+
{
290+
$binaryData = file_get_contents(__DIR__.'/Fixtures/arrow.gif');
291+
$expected = '{ data: !!binary '.base64_encode($binaryData).' }';
292+
293+
$this->assertSame($expected, $this->dumper->dump(array('data' => $binaryData), 0, 0, Yaml::DUMP_BASE64_BINARY_DATA));
294+
}
279295
}
280296

281297
class A
185 Bytes
Loading

‎src/Symfony/Component/Yaml/Tests/InlineTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Yaml/Tests/InlineTest.php
+37Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,4 +532,41 @@ public function getDateTimeDumpTests()
532532

533533
return $tests;
534534
}
535+
536+
/**
537+
* @dataProvider getBinaryData
538+
*/
539+
public function testParseBinaryData($data)
540+
{
541+
$this->assertSame('Hello world', Inline::parse($data));
542+
}
543+
544+
public function getBinaryData()
545+
{
546+
return array(
547+
'enclosed with double quotes' => array('!!binary "SGVsbG8gd29ybGQ="'),
548+
'enclosed with single quotes' => array("!!binary 'SGVsbG8gd29ybGQ='"),
549+
'containing spaces' => array('!!binary "SGVs bG8gd 29ybGQ="'),
550+
);
551+
}
552+
553+
/**
554+
* @dataProvider getInvalidBinaryData
555+
*/
556+
public function testParseInvalidBinaryData($data, $expectedMessage)
557+
{
558+
$this->setExpectedExceptionRegExp('\Symfony\Component\Yaml\Exception\ParseException', $expectedMessage);
559+
560+
Inline::parse($data);
561+
}
562+
563+
public function getInvalidBinaryData()
564+
{
565+
return array(
566+
'length not a multiple of four' => array('!!binary "SGVsbG8d29ybGQ="', '/The normalized base64 encoded data \(data without whitespace characters\) length must be a multiple of four \(\d+ bytes given\)/'),
567+
'invalid characters' => array('!!binary "SGVsbG8#d29ybGQ="', '/The base64 encoded data \(.*\) contains invalid characters/'),
568+
'too many equals characters' => array('!!binary "SGVsbG8gd29yb==="', '/The base64 encoded data \(.*\) contains invalid characters/'),
569+
'misplaced equals character' => array('!!binary "SGVsbG8gd29ybG=Q"', '/The base64 encoded data \(.*\) contains invalid characters/'),
570+
);
571+
}
535572
}

‎src/Symfony/Component/Yaml/Tests/ParserTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Yaml/Tests/ParserTest.php
+81Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,6 +1120,87 @@ public function testAdditionallyIndentedLinesAreParsedAsNewLinesInFoldedBlocks()
11201120
$this->parser->parse($yaml)
11211121
);
11221122
}
1123+
1124+
/**
1125+
* @dataProvider getBinaryData
1126+
*/
1127+
public function testParseBinaryData($data)
1128+
{
1129+
$this->assertSame(array('data' => 'Hello world'), $this->parser->parse($data));
1130+
}
1131+
1132+
public function getBinaryData()
1133+
{
1134+
return array(
1135+
'enclosed with double quotes' => array('data: !!binary "SGVsbG8gd29ybGQ="'),
1136+
'enclosed with single quotes' => array("data: !!binary 'SGVsbG8gd29ybGQ='"),
1137+
'containing spaces' => array('data: !!binary "SGVs bG8gd 29ybGQ="'),
1138+
'in block scalar' => array(
1139+
<<<EOT
1140+
data: !!binary |
1141+
SGVsbG8gd29ybGQ=
1142+
EOT
1143+
),
1144+
'containing spaces in block scalar' => array(
1145+
<<<EOT
1146+
data: !!binary |
1147+
SGVs bG8gd 29ybGQ=
1148+
EOT
1149+
),
1150+
);
1151+
}
1152+
1153+
/**
1154+
* @dataProvider getInvalidBinaryData
1155+
*/
1156+
public function testParseInvalidBinaryData($data, $expectedMessage)
1157+
{
1158+
$this->setExpectedExceptionRegExp('\Symfony\Component\Yaml\Exception\ParseException', $expectedMessage);
1159+
1160+
$this->parser->parse($data);
1161+
}
1162+
1163+
public function getInvalidBinaryData()
1164+
{
1165+
return array(
1166+
'length not a multiple of four' => array('data: !!binary "SGVsbG8d29ybGQ="', '/The normalized base64 encoded data \(data without whitespace characters\) length must be a multiple of four \(\d+ bytes given\)/'),
1167+
'invalid characters' => array('!!binary "SGVsbG8#d29ybGQ="', '/The base64 encoded data \(.*\) contains invalid characters/'),
1168+
'too many equals characters' => array('data: !!binary "SGVsbG8gd29yb==="', '/The base64 encoded data \(.*\) contains invalid characters/'),
1169+
'misplaced equals character' => array('data: !!binary "SGVsbG8gd29ybG=Q"', '/The base64 encoded data \(.*\) contains invalid characters/'),
1170+
'length not a multiple of four in block scalar' => array(
1171+
<<<EOT
1172+
data: !!binary |
1173+
SGVsbG8d29ybGQ=
1174+
EOT
1175+
,
1176+
'/The normalized base64 encoded data \(data without whitespace characters\) length must be a multiple of four \(\d+ bytes given\)/',
1177+
),
1178+
'invalid characters in block scalar' => array(
1179+
<<<EOT
1180+
data: !!binary |
1181+
SGVsbG8#d29ybGQ=
1182+
EOT
1183+
,
1184+
'/The base64 encoded data \(.*\) contains invalid characters/',
1185+
),
1186+
'too many equals characters in block scalar' => array(
1187+
<<<EOT
1188+
data: !!binary |
1189+
SGVsbG8gd29yb===
1190+
EOT
1191+
,
1192+
'/The base64 encoded data \(.*\) contains invalid characters/',
1193+
),
1194+
'misplaced equals character in block scalar' => array(
1195+
<<<EOT
1196+
data: !!binary |
1197+
SGVsbG8gd29ybG=Q
1198+
EOT
1199+
,
1200+
'/The base64 encoded data \(.*\) contains invalid characters/',
1201+
),
1202+
);
1203+
}
11231204
}
11241205

11251206
class B

‎src/Symfony/Component/Yaml/Yaml.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Yaml/Yaml.php
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class Yaml
2626
const PARSE_OBJECT_FOR_MAP = 8;
2727
const DUMP_EXCEPTION_ON_INVALID_TYPE = 16;
2828
const PARSE_DATETIME = 32;
29+
const DUMP_BASE64_BINARY_DATA = 64;
2930

3031
/**
3132
* Parses YAML into a PHP value.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.