PHP Datetime constructor returns now for strange values

I found that the PHP \ Datetime class returns "now" values ​​for some odd inputs. I already saw a similar question in the DateTime constructor in php - which explains input such as single letters of the alphabet (they are military time zones). But I discovered some new oddities that I would expect to cause an error rather than return a value. Such as...

new \Datetime( '.' )
new \Datetime( ',' )

Can someone explain why this is not causing errors, and can someone tell me what other odd values ​​I should expect to return valid dates? Is this a bug in PHP?

(Yes, I already noticed 0 and basically everything you find in timezone_abbreviations_list())

UPDATE

It seemed to me that I would share my "turning various inputs into a PHP Datetime object" with all of you. Originally made as a conditional “no matter what I passed, the output of the object”, but thanks to input @Syscall I was able to slow it down a bit from false inputs that improperly return “now” datetimes.

I could further strengthen this against different lines of the time zone, but I do not think that this is necessary for my use.

/**
 * If $input is already a DateTime object, leave it alone. Otherwise convert to a DateTime object
 * If $immutable = true, converts strings OR DateTime to DateTimeImmutable
 * Can be used to convert DateTimeInterface objects to and from immutable
 *
 * @param string|\DatetimeInterface $input
 * @param bool $immutable
 * @return \DateTime|\DateTimeImmutable|\DateTimeInterface|null
 */
function ensureDateTime ( $input, $immutable = NULL ) {
    if ( ! $input instanceof \DateTimeInterface ) {
        $output = NULL;
        if( is_string( $input ) || ! $input ) {
            $trimmed = trim( $input, ".,\n\0\t " ); // Thanks https://stackoverflow.com/a/48956505/339440
            $ignore =  ( $trimmed == '' && $trimmed != $input )
              || in_array( $trimmed, ['0000-00-00', '0000-00-00 00:00:00'], true )
              || ( strlen( $trimmed ) == 1 && preg_match( '#[a-zA-Z]#', $trimmed ) == 1 );
            if ( ! $ignore ) {
                try {
                    $input = trim( $input );
                    if ( $immutable ) {
                        $output = new \DateTimeImmutable( $input );
                    } else {
                        $output = new \DateTime( $input );
                    }
                } catch( \Exception $e ) {
                    // suppress DateTime::__construct() errors.  $output remains NULL
                }
            }
        }
    } elseif ( true === $immutable && $input instanceof \DateTime ) {
        $output = new \DateTimeImmutable( $input->format(TIMESTAMPFORMAT), $input->getTimezone() );
    } elseif ( false === $immutable && $input instanceof \DateTimeImmutable ) {
        $output = new \DateTime( $input->format(TIMESTAMPFORMAT), $input->getTimezone() );
    } else {
        $output = $input;
    }
    return $output;
}
+4
source share
1 answer

Values ​​are ".,\n\0\t "truncated:

Cm. /php-7.2.2/ext/date/lib/parse_date.c, static int scan():

switch (yych) {
case 0x00:
case '\n':  goto yy51;
case '\t':
case ' ':   goto yy48;
case ',':
case '.':   goto yy50;

Other characters, such as (+-@letters, numbers, require a different check.

Example:

new Datetime("\0 \n\t,."); // works

But:

new Datetime('@') ; // fails
+3
source

Source: https://habr.com/ru/post/1694070/


All Articles