Bug #83916

ViewHelper f:format.date can't handle unix timestamp > 2147483648

Added by Sven Burkert 10 months ago. Updated 9 months ago.

Status:
Needs Feedback
Priority:
Must have
Category:
Reports
Target version:
-
Start date:
Due date:
% Done:

0%

TYPO3 Version:
8
PHP Version:
7.0
Tags:
Fluid, timestamp, int, bigint
Complexity:
Is Regression:
Sprint Focus:

Description

This Fluid

<f:format.date>2247483648</f:format.date>

results in
#1241722579: "2247483648" could not be parsed by \DateTime constructor: DateTime::__construct(): Failed to parse time string (@) at position 0 (@): Unexpected character (More information)

Problem is function MathUtility::canBeInterpretedAsInteger in DateViewHelper, which checks the unix timestamp for integer. But unix timestamp is no integer, it can be much larger than an integer.

History

#1 Updated by Mathias Schreiber 10 months ago

  • Status changed from New to Accepted
  • Assignee set to Mathias Schreiber

please run this code on your machine:

<?php

function testInteger()
{
    return is_int(2247483648);
}

function buildDate()
{
    return new \DateTime('@' . 2247483648);
}

var_dump(testInteger());
var_dump(buildDate());

The result on my machine is:

/Volumes/Web/docRoot/typo3-core/Web/fileadmin/test.php:13:boolean true
/Volumes/Web/docRoot/typo3-core/Web/fileadmin/test.php:14:
object(DateTime)[1]
  public 'date' => string '2041-03-21 13:00:48.000000' (length=26)
  public 'timezone_type' => int 1
  public 'timezone' => string '+00:00' (length=6)

#2 Updated by Mathias Schreiber 10 months ago

I just added two 0 to the timestamp.

/Volumes/Web/docRoot/typo3-core/Web/fileadmin/test.php:13:boolean true
/Volumes/Web/docRoot/typo3-core/Web/fileadmin/test.php:14:
object(DateTime)[1]
  public 'date' => string '9091-12-29 05:20:00.000000' (length=26)
  public 'timezone_type' => int 1
  public 'timezone' => string '+00:00' (length=6)

Are you running a 32bit system?!?

#3 Updated by Mathias Schreiber 10 months ago

  • Status changed from Accepted to Needs Feedback

#4 Updated by Mathias Schreiber 10 months ago

  • Status changed from Needs Feedback to Closed

#5 Updated by Sven Burkert 10 months ago

I get

bool(false)
object(DateTime)#1 (3) { ["date"]=> string(26) "2041-03-21 13:00:48.000000" ["timezone_type"]=> int(1) ["timezone"]=> string(6) "+00:00" }

So is_int fails. I'm running a 64-bit system, but MAMP runs in 32-bit. But I'm getting the same results on a managed server from DomainFactory (nearly all DomainFactory servers run with 32-bit and I think from many other hosters, too).
But shouldn't TYPO3 also run on 32-bit systems? I can't find requirements for 64-bit (https://github.com/TYPO3/TYPO3.CMS/blob/TYPO3_8-7/INSTALL.md).

#6 Updated by Mathias Schreiber 10 months ago

What would be your proposed solution?
The scenarios I thought of:
  • remove is_int doesn't work because the VH accepts both strings and integer values and decides based on the input value
  • use is_numeric doesn't work because floats are numeric, too
  • introduce a new VH for UnixTimestamps and remove the old functionality would be a breaking change

#7 Updated by Stephan GroƟberndt 10 months ago

  • Status changed from Closed to Needs Feedback
  • Start date deleted (2018-02-15)
  • Complexity deleted (easy)

Hm, on 32-bit systems (32-bit PHP on 64-bit OS makes this 32-bit) you are bound to the int restrictions of 32-bit. With 32-bit you can't handle dates >year 2038 being represented by ints. So fluid would be able to cope with it but if you want to save those values in the database (assuming mysql running with 32-bit too) it will break again.

Another option I see is to adjust DateViewHelper:

  $base = $base instanceof \DateTimeInterface ? $base->format('U') : strtotime((MathUtility::canBeInterpretedAsInteger($base) ? '@' : '') . $base);
  $dateTimestamp = strtotime((MathUtility::canBeInterpretedAsInteger($date) ? '@' : '') . $date, $base);

Do not use MathUtility::canBeInterpretedAsInteger() (as apparently the number can be bigger as representable by int) but some other kind of check e.g. preg_match (slow) or is_numeric.

After some research I guess is_numeric is the way to go: According to http://php.net/manual/de/function.is-numeric.php#102011 is_numeric can handle very big numbers.

Could you please test this:

<?php

function testNumeric() {
    return is_numeric(2247483648);
}

function buildDate()
{
    return new \DateTime('@' . 2247483648);
}

var_dump(testNumeric());
var_dump(buildDate());

If that works

  $base = $base instanceof \DateTimeInterface ? $base->format('U') : strtotime((is_numeric($base) ? '@' : '') . $base);
  $dateTimestamp = strtotime((is_numeric($date) ? '@' : '') . $date, $base);

would be an appropriate patch

#8 Updated by Kevin Ditscheid 10 months ago

I have a splitted opinion about this one, because as soon as \DateTime::getTimestamp() will come in, all will break apart again. A real solution can only be the hoster updating its systems to a 64bit variant.

#9 Updated by Georg Ringer 10 months ago

so what about a report which sets a warning if 32bit is used?

#10 Updated by Claus Due 9 months ago

  • Category changed from Fluid to Reports

I suggest either closing this issue or turning it into a TASK to add a new report that warns about 32 bit systems, as suggested by Georg. I've taken the liberty of removing the Fluid category as this doesn't only pertain to Fluid - and assigning it to the Reports category.

Alternatively this may better belong in "core" if we need to somehow declare 64bit as hard requirement.

Also available in: Atom PDF