2016-05-07 12:59:40 +02:00
< ? php
/*
* This file is part of the Symfony package .
*
* ( c ) Fabien Potencier < fabien @ symfony . com >
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
namespace Symfony\Component\Yaml ;
use Symfony\Component\Yaml\Exception\ParseException ;
use Symfony\Component\Yaml\Exception\DumpException ;
/**
* Inline implements a YAML parser / dumper for the YAML inline syntax .
*
* @ author Fabien Potencier < fabien @ symfony . com >
2016-12-30 00:04:12 +01:00
*
* @ internal
2016-05-07 12:59:40 +02:00
*/
class Inline
{
const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\']*(?:\'\'[^\']*)*)\')' ;
2016-12-30 00:04:12 +01:00
public static $parsedLineNumber ;
2016-05-07 12:59:40 +02:00
private static $exceptionOnInvalidType = false ;
private static $objectSupport = false ;
private static $objectForMap = false ;
2016-12-30 00:04:12 +01:00
private static $constantSupport = false ;
2016-05-07 12:59:40 +02:00
/**
2016-12-30 00:04:12 +01:00
* Converts a YAML string to a PHP value .
2016-05-07 12:59:40 +02:00
*
2016-12-30 00:04:12 +01:00
* @ param string $value A YAML string
* @ param int $flags A bit field of PARSE_ * constants to customize the YAML parser behavior
* @ param array $references Mapping of variable names to values
2016-05-07 12:59:40 +02:00
*
2016-12-30 00:04:12 +01:00
* @ return mixed A PHP value
2016-05-07 12:59:40 +02:00
*
* @ throws ParseException
*/
2016-12-30 00:04:12 +01:00
public static function parse ( $value , $flags = 0 , $references = array ())
2016-05-07 12:59:40 +02:00
{
2016-12-30 00:04:12 +01:00
if ( is_bool ( $flags )) {
@ trigger_error ( 'Passing a boolean flag to toggle exception handling is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE flag instead.' , E_USER_DEPRECATED );
if ( $flags ) {
$flags = Yaml :: PARSE_EXCEPTION_ON_INVALID_TYPE ;
} else {
$flags = 0 ;
}
}
if ( func_num_args () >= 3 && ! is_array ( $references )) {
@ trigger_error ( 'Passing a boolean flag to toggle object support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT flag instead.' , E_USER_DEPRECATED );
if ( $references ) {
$flags |= Yaml :: PARSE_OBJECT ;
}
if ( func_num_args () >= 4 ) {
@ trigger_error ( 'Passing a boolean flag to toggle object for map support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT_FOR_MAP flag instead.' , E_USER_DEPRECATED );
if ( func_get_arg ( 3 )) {
$flags |= Yaml :: PARSE_OBJECT_FOR_MAP ;
}
}
if ( func_num_args () >= 5 ) {
$references = func_get_arg ( 4 );
} else {
$references = array ();
}
}
self :: $exceptionOnInvalidType = ( bool ) ( Yaml :: PARSE_EXCEPTION_ON_INVALID_TYPE & $flags );
self :: $objectSupport = ( bool ) ( Yaml :: PARSE_OBJECT & $flags );
self :: $objectForMap = ( bool ) ( Yaml :: PARSE_OBJECT_FOR_MAP & $flags );
self :: $constantSupport = ( bool ) ( Yaml :: PARSE_CONSTANT & $flags );
2016-05-07 12:59:40 +02:00
$value = trim ( $value );
if ( '' === $value ) {
return '' ;
}
if ( 2 /* MB_OVERLOAD_STRING */ & ( int ) ini_get ( 'mbstring.func_overload' )) {
$mbEncoding = mb_internal_encoding ();
mb_internal_encoding ( 'ASCII' );
}
$i = 0 ;
switch ( $value [ 0 ]) {
case '[' :
2016-12-30 00:04:12 +01:00
$result = self :: parseSequence ( $value , $flags , $i , $references );
2016-05-07 12:59:40 +02:00
++ $i ;
break ;
case '{' :
2016-12-30 00:04:12 +01:00
$result = self :: parseMapping ( $value , $flags , $i , $references );
2016-05-07 12:59:40 +02:00
++ $i ;
break ;
default :
2016-12-30 00:04:12 +01:00
$result = self :: parseScalar ( $value , $flags , null , array ( '"' , " ' " ), $i , true , $references );
2016-05-07 12:59:40 +02:00
}
// some comments are allowed at the end
if ( preg_replace ( '/\s+#.*$/A' , '' , substr ( $value , $i ))) {
throw new ParseException ( sprintf ( 'Unexpected characters near "%s".' , substr ( $value , $i )));
}
if ( isset ( $mbEncoding )) {
mb_internal_encoding ( $mbEncoding );
}
return $result ;
}
/**
* Dumps a given PHP variable to a YAML string .
*
2016-12-30 00:04:12 +01:00
* @ param mixed $value The PHP variable to convert
* @ param int $flags A bit field of Yaml :: DUMP_ * constants to customize the dumped YAML string
2016-05-07 12:59:40 +02:00
*
2016-12-30 00:04:12 +01:00
* @ return string The YAML string representing the PHP value
2016-05-07 12:59:40 +02:00
*
* @ throws DumpException When trying to dump PHP resource
*/
2016-12-30 00:04:12 +01:00
public static function dump ( $value , $flags = 0 )
2016-05-07 12:59:40 +02:00
{
2016-12-30 00:04:12 +01:00
if ( is_bool ( $flags )) {
@ trigger_error ( 'Passing a boolean flag to toggle exception handling is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE flag instead.' , E_USER_DEPRECATED );
if ( $flags ) {
$flags = Yaml :: DUMP_EXCEPTION_ON_INVALID_TYPE ;
} else {
$flags = 0 ;
}
}
if ( func_num_args () >= 3 ) {
@ trigger_error ( 'Passing a boolean flag to toggle object support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::DUMP_OBJECT flag instead.' , E_USER_DEPRECATED );
if ( func_get_arg ( 2 )) {
$flags |= Yaml :: DUMP_OBJECT ;
}
}
2016-05-07 12:59:40 +02:00
switch ( true ) {
case is_resource ( $value ) :
2016-12-30 00:04:12 +01:00
if ( Yaml :: DUMP_EXCEPTION_ON_INVALID_TYPE & $flags ) {
2016-05-07 12:59:40 +02:00
throw new DumpException ( sprintf ( 'Unable to dump PHP resources in a YAML file ("%s").' , get_resource_type ( $value )));
}
return 'null' ;
2016-12-30 00:04:12 +01:00
case $value instanceof \DateTimeInterface :
return $value -> format ( 'c' );
2016-05-07 12:59:40 +02:00
case is_object ( $value ) :
2016-12-30 00:04:12 +01:00
if ( Yaml :: DUMP_OBJECT & $flags ) {
2016-05-07 12:59:40 +02:00
return '!php/object:' . serialize ( $value );
}
2016-12-30 00:04:12 +01:00
if ( Yaml :: DUMP_OBJECT_AS_MAP & $flags && ( $value instanceof \stdClass || $value instanceof \ArrayObject )) {
return self :: dumpArray (( array ) $value , $flags );
}
if ( Yaml :: DUMP_EXCEPTION_ON_INVALID_TYPE & $flags ) {
2016-05-07 12:59:40 +02:00
throw new DumpException ( 'Object support when dumping a YAML file has been disabled.' );
}
return 'null' ;
case is_array ( $value ) :
2016-12-30 00:04:12 +01:00
return self :: dumpArray ( $value , $flags );
2016-05-07 12:59:40 +02:00
case null === $value :
return 'null' ;
case true === $value :
return 'true' ;
case false === $value :
return 'false' ;
case ctype_digit ( $value ) :
return is_string ( $value ) ? " ' $value ' " : ( int ) $value ;
case is_numeric ( $value ) :
$locale = setlocale ( LC_NUMERIC , 0 );
if ( false !== $locale ) {
setlocale ( LC_NUMERIC , 'C' );
}
if ( is_float ( $value )) {
$repr = ( string ) $value ;
if ( is_infinite ( $value )) {
$repr = str_ireplace ( 'INF' , '.Inf' , $repr );
} elseif ( floor ( $value ) == $value && $repr == $value ) {
// Preserve float data type since storing a whole number will result in integer value.
$repr = '!!float ' . $repr ;
}
} else {
$repr = is_string ( $value ) ? " ' $value ' " : ( string ) $value ;
}
if ( false !== $locale ) {
setlocale ( LC_NUMERIC , $locale );
}
return $repr ;
case '' == $value :
return " '' " ;
2016-12-30 00:04:12 +01:00
case self :: isBinaryString ( $value ) :
return '!!binary ' . base64_encode ( $value );
2016-05-07 12:59:40 +02:00
case Escaper :: requiresDoubleQuoting ( $value ) :
return Escaper :: escapeWithDoubleQuotes ( $value );
case Escaper :: requiresSingleQuoting ( $value ) :
2016-12-30 00:04:12 +01:00
case preg_match ( '{^[0-9]+[_0-9]*$}' , $value ) :
2016-05-07 12:59:40 +02:00
case preg_match ( self :: getHexRegex (), $value ) :
case preg_match ( self :: getTimestampRegex (), $value ) :
return Escaper :: escapeWithSingleQuotes ( $value );
default :
return $value ;
}
}
2016-12-30 00:04:12 +01:00
/**
* Check if given array is hash or just normal indexed array .
*
* @ internal
*
* @ param array $value The PHP array to check
*
* @ return bool true if value is hash array , false otherwise
*/
public static function isHash ( array $value )
{
$expectedKey = 0 ;
foreach ( $value as $key => $val ) {
if ( $key !== $expectedKey ++ ) {
return true ;
}
}
return false ;
}
2016-05-07 12:59:40 +02:00
/**
* Dumps a PHP array to a YAML string .
*
2016-12-30 00:04:12 +01:00
* @ param array $value The PHP array to dump
* @ param int $flags A bit field of Yaml :: DUMP_ * constants to customize the dumped YAML string
2016-05-07 12:59:40 +02:00
*
* @ return string The YAML string representing the PHP array
*/
2016-12-30 00:04:12 +01:00
private static function dumpArray ( $value , $flags )
2016-05-07 12:59:40 +02:00
{
// array
2016-12-30 00:04:12 +01:00
if ( $value && ! self :: isHash ( $value )) {
2016-05-07 12:59:40 +02:00
$output = array ();
foreach ( $value as $val ) {
2016-12-30 00:04:12 +01:00
$output [] = self :: dump ( $val , $flags );
2016-05-07 12:59:40 +02:00
}
return sprintf ( '[%s]' , implode ( ', ' , $output ));
}
2016-12-30 00:04:12 +01:00
// hash
2016-05-07 12:59:40 +02:00
$output = array ();
foreach ( $value as $key => $val ) {
2016-12-30 00:04:12 +01:00
$output [] = sprintf ( '%s: %s' , self :: dump ( $key , $flags ), self :: dump ( $val , $flags ));
2016-05-07 12:59:40 +02:00
}
return sprintf ( '{ %s }' , implode ( ', ' , $output ));
}
/**
2016-12-30 00:04:12 +01:00
* Parses a YAML scalar .
2016-05-07 12:59:40 +02:00
*
* @ param string $scalar
2016-12-30 00:04:12 +01:00
* @ param int $flags
2016-05-07 12:59:40 +02:00
* @ param string $delimiters
* @ param array $stringDelimiters
* @ param int & $i
* @ param bool $evaluate
* @ param array $references
*
2016-12-30 00:04:12 +01:00
* @ return string
2016-05-07 12:59:40 +02:00
*
* @ throws ParseException When malformed inline YAML string is parsed
*
* @ internal
*/
2016-12-30 00:04:12 +01:00
public static function parseScalar ( $scalar , $flags = 0 , $delimiters = null , $stringDelimiters = array ( '"' , " ' " ), & $i = 0 , $evaluate = true , $references = array ())
2016-05-07 12:59:40 +02:00
{
if ( in_array ( $scalar [ $i ], $stringDelimiters )) {
// quoted scalar
$output = self :: parseQuotedScalar ( $scalar , $i );
if ( null !== $delimiters ) {
$tmp = ltrim ( substr ( $scalar , $i ), ' ' );
if ( ! in_array ( $tmp [ 0 ], $delimiters )) {
throw new ParseException ( sprintf ( 'Unexpected characters (%s).' , substr ( $scalar , $i )));
}
}
} else {
// "normal" string
if ( ! $delimiters ) {
$output = substr ( $scalar , $i );
$i += strlen ( $output );
// remove comments
if ( preg_match ( '/[ \t]+#/' , $output , $match , PREG_OFFSET_CAPTURE )) {
$output = substr ( $output , 0 , $match [ 0 ][ 1 ]);
}
} elseif ( preg_match ( '/^(.+?)(' . implode ( '|' , $delimiters ) . ')/' , substr ( $scalar , $i ), $match )) {
$output = $match [ 1 ];
$i += strlen ( $output );
} else {
2016-12-30 00:04:12 +01:00
throw new ParseException ( sprintf ( 'Malformed inline YAML string: %s.' , $scalar ));
2016-05-07 12:59:40 +02:00
}
// a non-quoted string cannot start with @ or ` (reserved) nor with a scalar indicator (| or >)
if ( $output && ( '@' === $output [ 0 ] || '`' === $output [ 0 ] || '|' === $output [ 0 ] || '>' === $output [ 0 ])) {
throw new ParseException ( sprintf ( 'The reserved indicator "%s" cannot start a plain scalar; you need to quote the scalar.' , $output [ 0 ]));
}
2016-12-30 00:04:12 +01:00
if ( $output && '%' === $output [ 0 ]) {
@ trigger_error ( sprintf ( 'Not quoting the scalar "%s" starting with the "%%" indicator character is deprecated since Symfony 3.1 and will throw a ParseException in 4.0.' , $output ), E_USER_DEPRECATED );
}
2016-05-07 12:59:40 +02:00
if ( $evaluate ) {
2016-12-30 00:04:12 +01:00
$output = self :: evaluateScalar ( $output , $flags , $references );
2016-05-07 12:59:40 +02:00
}
}
return $output ;
}
/**
2016-12-30 00:04:12 +01:00
* Parses a YAML quoted scalar .
2016-05-07 12:59:40 +02:00
*
* @ param string $scalar
* @ param int & $i
*
2016-12-30 00:04:12 +01:00
* @ return string
2016-05-07 12:59:40 +02:00
*
* @ throws ParseException When malformed inline YAML string is parsed
*/
private static function parseQuotedScalar ( $scalar , & $i )
{
if ( ! preg_match ( '/' . self :: REGEX_QUOTED_STRING . '/Au' , substr ( $scalar , $i ), $match )) {
2016-12-30 00:04:12 +01:00
throw new ParseException ( sprintf ( 'Malformed inline YAML string: %s.' , substr ( $scalar , $i )));
2016-05-07 12:59:40 +02:00
}
$output = substr ( $match [ 0 ], 1 , strlen ( $match [ 0 ]) - 2 );
$unescaper = new Unescaper ();
if ( '"' == $scalar [ $i ]) {
$output = $unescaper -> unescapeDoubleQuotedString ( $output );
} else {
$output = $unescaper -> unescapeSingleQuotedString ( $output );
}
$i += strlen ( $match [ 0 ]);
return $output ;
}
/**
2016-12-30 00:04:12 +01:00
* Parses a YAML sequence .
2016-05-07 12:59:40 +02:00
*
* @ param string $sequence
2016-12-30 00:04:12 +01:00
* @ param int $flags
2016-05-07 12:59:40 +02:00
* @ param int & $i
* @ param array $references
*
2016-12-30 00:04:12 +01:00
* @ return array
2016-05-07 12:59:40 +02:00
*
* @ throws ParseException When malformed inline YAML string is parsed
*/
2016-12-30 00:04:12 +01:00
private static function parseSequence ( $sequence , $flags , & $i = 0 , $references = array ())
2016-05-07 12:59:40 +02:00
{
$output = array ();
$len = strlen ( $sequence );
++ $i ;
// [foo, bar, ...]
while ( $i < $len ) {
switch ( $sequence [ $i ]) {
case '[' :
// nested sequence
2016-12-30 00:04:12 +01:00
$output [] = self :: parseSequence ( $sequence , $flags , $i , $references );
2016-05-07 12:59:40 +02:00
break ;
case '{' :
// nested mapping
2016-12-30 00:04:12 +01:00
$output [] = self :: parseMapping ( $sequence , $flags , $i , $references );
2016-05-07 12:59:40 +02:00
break ;
case ']' :
return $output ;
case ',' :
case ' ' :
break ;
default :
$isQuoted = in_array ( $sequence [ $i ], array ( '"' , " ' " ));
2016-12-30 00:04:12 +01:00
$value = self :: parseScalar ( $sequence , $flags , array ( ',' , ']' ), array ( '"' , " ' " ), $i , true , $references );
2016-05-07 12:59:40 +02:00
// the value can be an array if a reference has been resolved to an array var
2016-12-30 00:04:12 +01:00
if ( is_string ( $value ) && ! $isQuoted && false !== strpos ( $value , ': ' )) {
2016-05-07 12:59:40 +02:00
// embedded mapping?
try {
$pos = 0 ;
2016-12-30 00:04:12 +01:00
$value = self :: parseMapping ( '{' . $value . '}' , $flags , $pos , $references );
2016-05-07 12:59:40 +02:00
} catch ( \InvalidArgumentException $e ) {
// no, it's not
}
}
$output [] = $value ;
-- $i ;
}
++ $i ;
}
2016-12-30 00:04:12 +01:00
throw new ParseException ( sprintf ( 'Malformed inline YAML string: %s.' , $sequence ));
2016-05-07 12:59:40 +02:00
}
/**
2016-12-30 00:04:12 +01:00
* Parses a YAML mapping .
2016-05-07 12:59:40 +02:00
*
* @ param string $mapping
2016-12-30 00:04:12 +01:00
* @ param int $flags
2016-05-07 12:59:40 +02:00
* @ param int & $i
* @ param array $references
*
2016-12-30 00:04:12 +01:00
* @ return array | \stdClass
2016-05-07 12:59:40 +02:00
*
* @ throws ParseException When malformed inline YAML string is parsed
*/
2016-12-30 00:04:12 +01:00
private static function parseMapping ( $mapping , $flags , & $i = 0 , $references = array ())
2016-05-07 12:59:40 +02:00
{
$output = array ();
$len = strlen ( $mapping );
++ $i ;
// {foo: bar, bar:foo, ...}
while ( $i < $len ) {
switch ( $mapping [ $i ]) {
case ' ' :
case ',' :
++ $i ;
continue 2 ;
case '}' :
if ( self :: $objectForMap ) {
return ( object ) $output ;
}
return $output ;
}
// key
2016-12-30 00:04:12 +01:00
$key = self :: parseScalar ( $mapping , $flags , array ( ':' , ' ' ), array ( '"' , " ' " ), $i , false );
if ( false === $i = strpos ( $mapping , ':' , $i )) {
break ;
}
if ( ! isset ( $mapping [ $i + 1 ]) || ! in_array ( $mapping [ $i + 1 ], array ( ' ' , '[' , ']' , '{' , '}' ), true )) {
@ trigger_error ( 'Using a colon that is not followed by an indication character (i.e. " ", ",", "[", "]", "{", "}" is deprecated since version 3.2 and will throw a ParseException in 4.0.' , E_USER_DEPRECATED );
}
2016-05-07 12:59:40 +02:00
// value
$done = false ;
while ( $i < $len ) {
switch ( $mapping [ $i ]) {
case '[' :
// nested sequence
2016-12-30 00:04:12 +01:00
$value = self :: parseSequence ( $mapping , $flags , $i , $references );
2016-05-07 12:59:40 +02:00
// Spec: Keys MUST be unique; first one wins.
// Parser cannot abort this mapping earlier, since lines
// are processed sequentially.
if ( ! isset ( $output [ $key ])) {
$output [ $key ] = $value ;
2016-12-30 00:04:12 +01:00
} else {
@ trigger_error ( sprintf ( 'Duplicate key "%s" detected on line %d whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.' , $key , self :: $parsedLineNumber + 1 ), E_USER_DEPRECATED );
2016-05-07 12:59:40 +02:00
}
$done = true ;
break ;
case '{' :
// nested mapping
2016-12-30 00:04:12 +01:00
$value = self :: parseMapping ( $mapping , $flags , $i , $references );
2016-05-07 12:59:40 +02:00
// Spec: Keys MUST be unique; first one wins.
// Parser cannot abort this mapping earlier, since lines
// are processed sequentially.
if ( ! isset ( $output [ $key ])) {
$output [ $key ] = $value ;
2016-12-30 00:04:12 +01:00
} else {
@ trigger_error ( sprintf ( 'Duplicate key "%s" detected on line %d whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.' , $key , self :: $parsedLineNumber + 1 ), E_USER_DEPRECATED );
2016-05-07 12:59:40 +02:00
}
$done = true ;
break ;
case ':' :
case ' ' :
break ;
default :
2016-12-30 00:04:12 +01:00
$value = self :: parseScalar ( $mapping , $flags , array ( ',' , '}' ), array ( '"' , " ' " ), $i , true , $references );
2016-05-07 12:59:40 +02:00
// Spec: Keys MUST be unique; first one wins.
// Parser cannot abort this mapping earlier, since lines
// are processed sequentially.
if ( ! isset ( $output [ $key ])) {
$output [ $key ] = $value ;
2016-12-30 00:04:12 +01:00
} else {
@ trigger_error ( sprintf ( 'Duplicate key "%s" detected on line %d whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.' , $key , self :: $parsedLineNumber + 1 ), E_USER_DEPRECATED );
2016-05-07 12:59:40 +02:00
}
$done = true ;
-- $i ;
}
++ $i ;
if ( $done ) {
continue 2 ;
}
}
}
2016-12-30 00:04:12 +01:00
throw new ParseException ( sprintf ( 'Malformed inline YAML string: %s.' , $mapping ));
2016-05-07 12:59:40 +02:00
}
/**
* Evaluates scalars and replaces magic values .
*
* @ param string $scalar
2016-12-30 00:04:12 +01:00
* @ param int $flags
2016-05-07 12:59:40 +02:00
* @ param array $references
*
* @ return string A YAML string
*
* @ throws ParseException when object parsing support was disabled and the parser detected a PHP object or when a reference could not be resolved
*/
2016-12-30 00:04:12 +01:00
private static function evaluateScalar ( $scalar , $flags , $references = array ())
2016-05-07 12:59:40 +02:00
{
$scalar = trim ( $scalar );
$scalarLower = strtolower ( $scalar );
if ( 0 === strpos ( $scalar , '*' )) {
if ( false !== $pos = strpos ( $scalar , '#' )) {
$value = substr ( $scalar , 1 , $pos - 2 );
} else {
$value = substr ( $scalar , 1 );
}
// an unquoted *
if ( false === $value || '' === $value ) {
throw new ParseException ( 'A reference must contain at least one character.' );
}
if ( ! array_key_exists ( $value , $references )) {
throw new ParseException ( sprintf ( 'Reference "%s" does not exist.' , $value ));
}
return $references [ $value ];
}
switch ( true ) {
case 'null' === $scalarLower :
case '' === $scalar :
case '~' === $scalar :
return ;
case 'true' === $scalarLower :
return true ;
case 'false' === $scalarLower :
return false ;
// Optimise for returning strings.
case $scalar [ 0 ] === '+' || $scalar [ 0 ] === '-' || $scalar [ 0 ] === '.' || $scalar [ 0 ] === '!' || is_numeric ( $scalar [ 0 ]) :
switch ( true ) {
case 0 === strpos ( $scalar , '!str' ) :
return ( string ) substr ( $scalar , 5 );
case 0 === strpos ( $scalar , '! ' ) :
2016-12-30 00:04:12 +01:00
return ( int ) self :: parseScalar ( substr ( $scalar , 2 ), $flags );
2016-05-07 12:59:40 +02:00
case 0 === strpos ( $scalar , '!php/object:' ) :
if ( self :: $objectSupport ) {
return unserialize ( substr ( $scalar , 12 ));
}
if ( self :: $exceptionOnInvalidType ) {
throw new ParseException ( 'Object support when parsing a YAML file has been disabled.' );
}
return ;
case 0 === strpos ( $scalar , '!!php/object:' ) :
if ( self :: $objectSupport ) {
2016-12-30 00:04:12 +01:00
@ trigger_error ( 'The !!php/object tag to indicate dumped PHP objects is deprecated since version 3.1 and will be removed in 4.0. Use the !php/object tag instead.' , E_USER_DEPRECATED );
2016-05-07 12:59:40 +02:00
return unserialize ( substr ( $scalar , 13 ));
}
if ( self :: $exceptionOnInvalidType ) {
throw new ParseException ( 'Object support when parsing a YAML file has been disabled.' );
}
2016-12-30 00:04:12 +01:00
return ;
case 0 === strpos ( $scalar , '!php/const:' ) :
if ( self :: $constantSupport ) {
if ( defined ( $const = substr ( $scalar , 11 ))) {
return constant ( $const );
}
throw new ParseException ( sprintf ( 'The constant "%s" is not defined.' , $const ));
}
if ( self :: $exceptionOnInvalidType ) {
throw new ParseException ( sprintf ( 'The string "%s" could not be parsed as a constant. Have you forgotten to pass the "Yaml::PARSE_CONSTANT" flag to the parser?' , $scalar ));
}
2016-05-07 12:59:40 +02:00
return ;
case 0 === strpos ( $scalar , '!!float ' ) :
return ( float ) substr ( $scalar , 8 );
2016-12-30 00:04:12 +01:00
case preg_match ( '{^[+-]?[0-9][0-9_]*$}' , $scalar ) :
$scalar = str_replace ( '_' , '' , ( string ) $scalar );
// omitting the break / return as integers are handled in the next case
2016-05-07 12:59:40 +02:00
case ctype_digit ( $scalar ) :
$raw = $scalar ;
$cast = ( int ) $scalar ;
return '0' == $scalar [ 0 ] ? octdec ( $scalar ) : ((( string ) $raw == ( string ) $cast ) ? $cast : $raw );
case '-' === $scalar [ 0 ] && ctype_digit ( substr ( $scalar , 1 )) :
$raw = $scalar ;
$cast = ( int ) $scalar ;
return '0' == $scalar [ 1 ] ? octdec ( $scalar ) : ((( string ) $raw === ( string ) $cast ) ? $cast : $raw );
case is_numeric ( $scalar ) :
case preg_match ( self :: getHexRegex (), $scalar ) :
2016-12-30 00:04:12 +01:00
$scalar = str_replace ( '_' , '' , $scalar );
2016-05-07 12:59:40 +02:00
return '0x' === $scalar [ 0 ] . $scalar [ 1 ] ? hexdec ( $scalar ) : ( float ) $scalar ;
case '.inf' === $scalarLower :
case '.nan' === $scalarLower :
return - log ( 0 );
case '-.inf' === $scalarLower :
return log ( 0 );
2016-12-30 00:04:12 +01:00
case 0 === strpos ( $scalar , '!!binary ' ) :
return self :: evaluateBinaryScalar ( substr ( $scalar , 9 ));
case preg_match ( '/^(-|\+)?[0-9][0-9,]*(\.[0-9_]+)?$/' , $scalar ) :
case preg_match ( '/^(-|\+)?[0-9][0-9_]*(\.[0-9_]+)?$/' , $scalar ) :
if ( false !== strpos ( $scalar , ',' )) {
@ trigger_error ( 'Using the comma as a group separator for floats is deprecated since version 3.2 and will be removed in 4.0.' , E_USER_DEPRECATED );
}
return ( float ) str_replace ( array ( ',' , '_' ), '' , $scalar );
2016-05-07 12:59:40 +02:00
case preg_match ( self :: getTimestampRegex (), $scalar ) :
2016-12-30 00:04:12 +01:00
if ( Yaml :: PARSE_DATETIME & $flags ) {
// When no timezone is provided in the parsed date, YAML spec says we must assume UTC.
return new \DateTime ( $scalar , new \DateTimeZone ( 'UTC' ));
}
2016-05-07 12:59:40 +02:00
$timeZone = date_default_timezone_get ();
date_default_timezone_set ( 'UTC' );
$time = strtotime ( $scalar );
date_default_timezone_set ( $timeZone );
return $time ;
}
default :
return ( string ) $scalar ;
}
}
2016-12-30 00:04:12 +01:00
/**
* @ param string $scalar
*
* @ return string
*
* @ internal
*/
public static function evaluateBinaryScalar ( $scalar )
{
$parsedBinaryData = self :: parseScalar ( preg_replace ( '/\s/' , '' , $scalar ));
if ( 0 !== ( strlen ( $parsedBinaryData ) % 4 )) {
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 )));
}
if ( ! preg_match ( '#^[A-Z0-9+/]+={0,2}$#i' , $parsedBinaryData )) {
throw new ParseException ( sprintf ( 'The base64 encoded data (%s) contains invalid characters.' , $parsedBinaryData ));
}
return base64_decode ( $parsedBinaryData , true );
}
private static function isBinaryString ( $value )
{
return ! preg_match ( '//u' , $value ) || preg_match ( '/[^\x09-\x0d\x20-\xff]/' , $value );
}
2016-05-07 12:59:40 +02:00
/**
* Gets a regex that matches a YAML date .
*
* @ return string The regular expression
*
* @ see http :// www . yaml . org / spec / 1.2 / spec . html #id2761573
*/
private static function getTimestampRegex ()
{
return <<< EOF
~^
( ? P < year > [ 0 - 9 ][ 0 - 9 ][ 0 - 9 ][ 0 - 9 ])
- ( ? P < month > [ 0 - 9 ][ 0 - 9 ] ? )
- ( ? P < day > [ 0 - 9 ][ 0 - 9 ] ? )
( ? : ( ? : [ Tt ] | [ \t ] + )
( ? P < hour > [ 0 - 9 ][ 0 - 9 ] ? )
: ( ? P < minute > [ 0 - 9 ][ 0 - 9 ])
: ( ? P < second > [ 0 - 9 ][ 0 - 9 ])
( ? : \ . ( ? P < fraction > [ 0 - 9 ] * )) ?
( ? : [ \t ] * ( ? P < tz > Z | ( ? P < tz_sign > [ -+ ])( ? P < tz_hour > [ 0 - 9 ][ 0 - 9 ] ? )
( ? :: ( ? P < tz_minute > [ 0 - 9 ][ 0 - 9 ])) ? )) ? ) ?
$ ~ x
EOF ;
}
/**
* Gets a regex that matches a YAML number in hexadecimal notation .
*
* @ return string
*/
private static function getHexRegex ()
{
2016-12-30 00:04:12 +01:00
return '~^0x[0-9a-f_]++$~i' ;
2016-05-07 12:59:40 +02:00
}
}