Home » Php » PHP – Setting up/emulating fake date

PHP – Setting up/emulating fake date

Posted by: admin July 12, 2020 Leave a comment

Questions:

I have a bit weird question. Is it possible to set up fake date in PHP for the time in which script is working? I am using API which uses time periods, for example when you send request to get some data, you can specify time period (for example one month, but these periods are fixed) and it will return results from request_time-1month to request_time. Obviously, request data is present time, so I want to emulate this present time (for example set date from 10 May to 15 April). Is it possible? I can’t see anything helpful in PHP documention and I don’t even know if it would work, because I’m not sure if this API uses time from server in which it works or independent server which stores aforementioned data. But maybe someone has any idea.

Thanks from advance.

How to&Answers:

If the API you are connecting to is using “request_time – 1 month”, then what your script thinks the time is isn’t relevant, only what time the script behind the API thinks it is. (As a silly analogy: if a shop closes at 5PM, setting your watch early won’t let you in at 5:30; you’d need to sneak in and change the clock on the wall so that the staff don’t lock up.)

So unless you can find a way to fool the remote API into thinking you sent the request at a different time, there is nothing you can do.

If you control the API, then just edit the API to have a parameter which over-rides the definition of “now”, perhaps only allowed in a special debug mode.

Answer:

Use libfaketime (https://github.com/wolfcw/libfaketime). On ubuntu – just install faketime using apt-get or aptitude.

  1. If you want to fake time for console app:

    LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1 FAKETIME="2008-01-01 00:00:00" php yourscript.php
    
  2. If you want to fake apache time, you will need to start apache with libfaketime preloaded. Just put

    export FAKETIME="2008-01-01 00:00:00"
    export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1
    

into /etc/apache2/envvars and restart apache. Now your server response will always look like

$ curl -D - http://localhost
HTTP/1.1 200 OK
Date: Tue, 01 Jan 2008 00:00:00 GMT
Server: Apache/2.2.22 (Ubuntu)
Last-Modified: Tue, 01 Jan 2008 00:00:00 GMT
ETag: W/"420419-b1-4429c2a6653ac"
Accept-Ranges: bytes
Content-Length: 177
Vary: Accept-Encoding
Content-Type: text/html

2019 UPDATE :

On the latest systems, you would need a 64-bit version of libfaketime so you’d need LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1 (thanks @jtrautmann), or even libfaketimeMT.so.1 in a multithreaded environment.

Also, there are three ways to specify the faked time:

  • By setting the environment variable FAKETIME
  • By using the file given in the environment variable FAKETIME_TIMESTAMP_FILE
  • By using the file .faketimerc in your home directory
  • By using the file /etc/faketimerc for a system-wide default

Also, it is perfectly valid to use libfaketime inside a docker container.

Answer:

Effectively, the date and time you access through PHP is the server’s system time. So if you are able to change that, you can achieve what you need. Have a look at this answer: https://stackoverflow.com/a/3923946/977431

Although personally, i would recommend just using a function which returns -30 days (for example) from the current date. When you would like to change the date back, replace the function with the real getdate().

Answer:

What exactly are you trying to do? If you’re testing something, you shouldn’t rely on system configuration at all – better to do something like:

my_function(\DateTime $now = null) {

  if($now === null) {
      return new \DateTime();
  } else {
      return $now;
  }

}

In your normal code, you just call my_function(), but in your test, you call

$now = \DateTime::createFromFormat(...);
my_function($now);

Similar idea if it’s for production code. Pass the date in as a parameter, instead of leaving the function to get it.

my_function(\DateTime $datetime) {
  // does stuff
}
call_my_function() {
  my_function(new \DateTime());
}
other_way_to_call_my_function() {
  $datetime = \DateTime::createFromFormat(...);
  my_function($datetime);
}