@@ -224,10 +224,11 @@ private function lexValue()
224
224
throw $ this ->createFormatException ('Missing quote to end the value ' );
225
225
}
226
226
++$ this ->cursor ;
227
- $ value = str_replace (array ('\\\\' , '\\ " ' , '\r ' , '\n ' ), array ('\\' , '" ' , "\r" , "\n" ), $ value );
227
+ $ value = str_replace (array ('\\" ' , '\r ' , '\n ' ), array ('" ' , "\r" , "\n" ), $ value );
228
228
$ resolvedValue = $ value ;
229
229
$ resolvedValue = $ this ->resolveVariables ($ resolvedValue );
230
230
$ resolvedValue = $ this ->resolveCommands ($ resolvedValue );
231
+ $ resolvedValue = str_replace ('\\\\' , '\\' , $ resolvedValue );
231
232
$ v .= $ resolvedValue ;
232
233
} else {
233
234
$ value = '' ;
@@ -250,6 +251,7 @@ private function lexValue()
250
251
$ resolvedValue = $ value ;
251
252
$ resolvedValue = $ this ->resolveVariables ($ resolvedValue );
252
253
$ resolvedValue = $ this ->resolveCommands ($ resolvedValue );
254
+ $ resolvedValue = str_replace ('\\\\' , '\\' , $ resolvedValue );
253
255
254
256
if ($ resolvedValue === $ value && preg_match ('/\s+/ ' , $ value )) {
255
257
throw $ this ->createFormatException ('A value containing spaces must be surrounded by quotes ' );
@@ -350,24 +352,31 @@ private function resolveVariables($value)
350
352
}
351
353
352
354
$ regex = '/
353
- ( \\\\)? # escaped with a backslash?
355
+ (?<! \\\\)
356
+ (?P<backslashes> \\\\*) # escaped with a backslash?
354
357
\$
355
- (?!\() # no opening parenthesis
356
- (\{)? # optional brace
357
- ( ' .self ::VARNAME_REGEX .') # var name
358
- (\})? # optional closing brace
358
+ (?!\() # no opening parenthesis
359
+ (?P<opening_brace> \{)? # optional brace
360
+ (?P<name> ' .self ::VARNAME_REGEX .')? # var name
361
+ (?P<closing_brace> \})? # optional closing brace
359
362
/x ' ;
360
363
361
364
$ value = preg_replace_callback ($ regex , function ($ matches ) {
362
- if ('\\' === $ matches [1 ]) {
365
+ // odd number of backslashes means the $ character is escaped
366
+ if (1 === \strlen ($ matches ['backslashes ' ]) % 2 ) {
363
367
return substr ($ matches [0 ], 1 );
364
368
}
365
369
366
- if ('{ ' === $ matches [2 ] && !isset ($ matches [4 ])) {
370
+ // unescaped $ not followed by variable name
371
+ if (!isset ($ matches ['name ' ])) {
372
+ return $ matches [0 ];
373
+ }
374
+
375
+ if ('{ ' === $ matches ['opening_brace ' ] && !isset ($ matches ['closing_brace ' ])) {
367
376
throw $ this ->createFormatException ('Unclosed braces on variable expansion ' );
368
377
}
369
378
370
- $ name = $ matches [3 ];
379
+ $ name = $ matches [' name ' ];
371
380
if (isset ($ this ->values [$ name ])) {
372
381
$ value = $ this ->values [$ name ];
373
382
} elseif (isset ($ _SERVER [$ name ]) && 0 !== strpos ($ name , 'HTTP_ ' )) {
@@ -378,15 +387,14 @@ private function resolveVariables($value)
378
387
$ value = (string ) getenv ($ name );
379
388
}
380
389
381
- if (!$ matches [2 ] && isset ($ matches [4 ])) {
390
+ if (!$ matches [' opening_brace ' ] && isset ($ matches [' closing_brace ' ])) {
382
391
$ value .= '} ' ;
383
392
}
384
393
385
- return $ value ;
394
+ return $ matches [ ' backslashes ' ]. $ value ;
386
395
}, $ value );
387
396
388
- // unescape
8000
$
389
- return str_replace ('\\$ ' , '$ ' , $ value );
397
+ return $ value ;
390
398
}
391
399
392
400
private function moveCursor ($ text )
0 commit comments