Posted in March 2014

Strtotime, PHP, and the End of the Month

Some of our PHP tests at Mover started failing today. In particular they were tests around our account system looking at the start and expiration dates for our plans:

1) Authenticator::->subscriptionStartDate::should be close to now
expected 1396389125 to be within 1396302607..1396302727

Some quick calculation shows that the date returned in the tests was 86518 seconds outside of the expected window, coincidentally close to the number of seconds in a day (86400).

It turns out this is a fairly widely discussed complication of the strtotime function in PHP, which we use to calculate the expiration and renewal periods for our plans. Our code to calculate the expiration date for a plan looks something like this:

<?php
date_default_timezone_set('UTC');
$now = time();
$expiration =  strtotime(date(\DateTime::W3C, $now) . " + 1 month");

Then later when we want to generate the subscription start date we subtract 1 month from the expiration date (why store redundant information in your database?)

$start_time =  strtotime(date(\DateTime::W3C, $expiration) . " - 1 month");

This, however, can yield some unexpected results:

$now
2014-03-31T21:58:43+00:00
 
($now + 1 month)
2014-05-01T21:58:43+00:00
 
($now + 1 month) - 1 month
2014-04-01T21:58:43+00:00

This is because of how PHP’s strtotime() function handles adding one month to a date for which the date does not exist in the next month. For example, if someone subscribed on January 31st, strtotime() will tell me that 1 month after January 31st is March 3rd. Personally this logic surprised me (and apparently many others). Fortunately we are already in the process of porting our account system to Recurly, which handles this problem in a very intuitive way. From Recurly’s FAQ:

Customers are always charged on the closest corresponding date of the following month. For example, a customer who would normally be billed on the 31st of a month will either be billed on the 30th of a 30 day month, or on the 28th of February.

Tagged , , , , , ,

WordPress PHP Files Downloading Instead of Processed by Server

I was helping a friend who was migrating a WordPress site from one host to another. After moving the files over to the new hosting provider instead of the files being server as PHP files by the web server a download prompt would pop-up to download a file. It turns out this was caused by the .htaccess file from the initial host (that was transferred along with the other files) not being properly configured for the new host. Here’s the initial .htaccess file:

# Use PHP5.4 as default
AddHandler application/x-httpd-php54 .php
 
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
 
# END WordPress

Note the AddHandler directive at the top of the file. My attention was drawn to it as the rest of the .htaccess file are the basic directives required by WordPress. This was likely added by the initial host to default .php files to be handled by PHP 5.4. The new host didn’t have support for PHP 5.4, which caused .php files to be mishandled. The issue was resolved by commenting out the line:

# Use PHP5.4 as default
# AddHandler application/x-httpd-php54 .php
 
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
 
# END WordPress

With this change the site began to function properly.

Tagged , , , , , , ,