Unescaper.php (4055B)
1 <?php 2 3 /* 4 * This file is part of the Symfony package. 5 * 6 * (c) Fabien Potencier <fabien@symfony.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12 namespace Symfony\Component\Yaml; 13 14 /** 15 * Unescaper encapsulates unescaping rules for single and double-quoted 16 * YAML strings. 17 * 18 * @author Matthew Lewinski <matthew@lewinski.org> 19 */ 20 class Unescaper 21 { 22 /** 23 * Parser and Inline assume UTF-8 encoding, so escaped Unicode characters 24 * must be converted to that encoding. 25 * 26 * @deprecated since version 2.5, to be removed in 3.0 27 * 28 * @internal 29 */ 30 const ENCODING = 'UTF-8'; 31 32 /** 33 * Regex fragment that matches an escaped character in a double quoted string. 34 */ 35 const REGEX_ESCAPED_CHARACTER = "\\\\([0abt\tnvfre \\\"\\/\\\\N_LP]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})"; 36 37 /** 38 * Unescapes a single quoted string. 39 * 40 * @param string $value A single quoted string. 41 * 42 * @return string The unescaped string. 43 */ 44 public function unescapeSingleQuotedString($value) 45 { 46 return str_replace('\'\'', '\'', $value); 47 } 48 49 /** 50 * Unescapes a double quoted string. 51 * 52 * @param string $value A double quoted string. 53 * 54 * @return string The unescaped string. 55 */ 56 public function unescapeDoubleQuotedString($value) 57 { 58 $self = $this; 59 $callback = function ($match) use ($self) { 60 return $self->unescapeCharacter($match[0]); 61 }; 62 63 // evaluate the string 64 return preg_replace_callback('/'.self::REGEX_ESCAPED_CHARACTER.'/u', $callback, $value); 65 } 66 67 /** 68 * Unescapes a character that was found in a double-quoted string. 69 * 70 * @param string $value An escaped character 71 * 72 * @return string The unescaped character 73 */ 74 public function unescapeCharacter($value) 75 { 76 switch ($value{1}) { 77 case '0': 78 return "\x0"; 79 case 'a': 80 return "\x7"; 81 case 'b': 82 return "\x8"; 83 case 't': 84 return "\t"; 85 case "\t": 86 return "\t"; 87 case 'n': 88 return "\n"; 89 case 'v': 90 return "\xB"; 91 case 'f': 92 return "\xC"; 93 case 'r': 94 return "\r"; 95 case 'e': 96 return "\x1B"; 97 case ' ': 98 return ' '; 99 case '"': 100 return '"'; 101 case '/': 102 return '/'; 103 case '\\': 104 return '\\'; 105 case 'N': 106 // U+0085 NEXT LINE 107 return "\xC2\x85"; 108 case '_': 109 // U+00A0 NO-BREAK SPACE 110 return "\xC2\xA0"; 111 case 'L': 112 // U+2028 LINE SEPARATOR 113 return "\xE2\x80\xA8"; 114 case 'P': 115 // U+2029 PARAGRAPH SEPARATOR 116 return "\xE2\x80\xA9"; 117 case 'x': 118 return self::utf8chr(hexdec(substr($value, 2, 2))); 119 case 'u': 120 return self::utf8chr(hexdec(substr($value, 2, 4))); 121 case 'U': 122 return self::utf8chr(hexdec(substr($value, 2, 8))); 123 } 124 } 125 126 /** 127 * Get the UTF-8 character for the given code point. 128 * 129 * @param int $c The unicode code point 130 * 131 * @return string The corresponding UTF-8 character 132 */ 133 private static function utf8chr($c) 134 { 135 if (0x80 > $c %= 0x200000) { 136 return chr($c); 137 } 138 if (0x800 > $c) { 139 return chr(0xC0 | $c >> 6).chr(0x80 | $c & 0x3F); 140 } 141 if (0x10000 > $c) { 142 return chr(0xE0 | $c >> 12).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F); 143 } 144 145 return chr(0xF0 | $c >> 18).chr(0x80 | $c >> 12 & 0x3F).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F); 146 } 147 }