PHP Timezone database is corrupt error
Asked Answered
H

7

12

I have a wordpress website which suddenly stopped working today. When I look at the logs I see and error:

[error] [client 50.78.108.177] PHP Fatal error: strtotime(): Timezone database is corrupt - this should never happen!

After reading up on google one person said that they discovered a permissions problem in /usr/share/zoneinfo. I tried changing the permissions to 777, 775, 770 and I still keep on getting the same error. I am running php PHP 5.3.2 on Ubuntu 10.04.3 LTS. Any suggestions or recommendations would be helpful.If all else fails I'm going to try downgrading to an earlier version of php but I wanted to try other things before doing that.

thanks, Timnit

Update
just in case it helps: the error points to strtotime in the function below

function mysql2date( $dateformatstring, $mysqlstring, $translate = true ) {
    $m = $mysqlstring;
    if ( empty( $m ) )
            return false;

    if ( 'G' == $dateformatstring )
            return strtotime( $m . ' +0000' );

    $i = strtotime( $m );

    if ( 'U' == $dateformatstring )
            return $i;

    if ( $translate )
            return date_i18n( $dateformatstring, $i );
    else
            return date( $dateformatstring, $i );
}

Update#2:
for now I have fixed the problem by simply having the function above return false; without performing anything. However I still haven't figured out the root cause of the problem.

update#3:

var_dump($dateformatstring)

string(5) "d.m.y" string(1) "m" string(5) "d.m.y" string(1) "m" string(5) "d.m.y" string(1) "m"

var_dump($mysqlstring)

string(19) "2011-10-20 05:35:01" string(19) "2011-10-20 05:35:01" string(19) "2011-10-20 05:25:22" string(19) "2011-10-20 05:25:22" string(19) "2011-10-19 05:10:06" string(19) "2011-10-19 05:10:06"

update#4:
there is another code snippet that is generating the error log below:

PHP Fatal error: date(): Timezone database is corrupt - this should never happen! in /srv/www/motionthink.com/public_html/wp-admin/includes/class-wp-filesystem-direct.php on line 346, referer: wp_root_directory/wp-admin/plugins.php?plugin_status=upgrade

309         function dirlist($path, $include_hidden = true, $recursive = false) {
  310                 if ( $this->is_file($path) ) {
  311                         $limit_file = basename($path);
  312                         $path = dirname($path);
  313                 } else {
  314                         $limit_file = false;
  315                 }
  316 
  317                 if ( ! $this->is_dir($path) )
  318                         return false;
  319 
  320                 $dir = @dir($path);
  321                 if ( ! $dir )
  322                         return false;
  323 
  324                 $ret = array();
  325 
  326                 while (false !== ($entry = $dir->read()) ) {
  327                         $struc = array();
  328                         $struc['name'] = $entry;
  329 
  330                         if ( '.' == $struc['name'] || '..' == $struc['name'] )
  331                                 continue;
  332 
  333                         if ( ! $include_hidden && '.' == $struc['name'][0] )
  334                                 continue;
  335 
  336                         if ( $limit_file && $struc['name'] != $limit_file)
  337                                 continue;
  338 
  339                         $struc['perms']         = $this->gethchmod($path.'/'.$entry);
  340                         $struc['permsn']  = $this->getnumchmodfromh($struc['perms']);
  341                         $struc['number']        = false;
  342                         $struc['owner']         = $this->owner($path.'/'.$entry);
  343                         $struc['group']         = $this->group($path.'/'.$entry);
  344                         $struc['size']          = $this->size($path.'/'.$entry);
  345                         $struc['lastmodunix']= $this->mtime($path.'/'.$entry);
  346                         $struc['lastmod']   = date('M j',$struc['lastmodunix']);
  347                         $struc['time']          = date('h:i:s',$struc['lastmodunix']);
  348                  $struc['type']          = $this->is_dir($path.'/'.$entry) ?   'd:'f';
  349 

Update#5:
doing a php -i | fgrep -i date returns

Build Date => Dec 13 2011 18:43:02

date
date/time support => enabled
date.default_latitude => 31.7667 => 31.7667
date.default_longitude => 35.2333 => 35.2333
date.sunrise_zenith => 90.583333 => 90.583333
date.sunset_zenith => 90.583333 => 90.583333
date.timezone => no value => no value

then I edited the php.ini file to set the timezone to "America/Los Angeles" and got this output

date/time support => enabled
date.default_latitude => 31.7667 => 31.7667
date.default_longitude => 35.2333 => 35.2333
date.sunrise_zenith => 90.583333 => 90.583333
date.sunset_zenith => 90.583333 => 90.583333
date.timezone => America/Los_Angeles => America/Los_Angeles

I then restarted apache2. I still get the error

Hindquarter answered 5/1, 2012 at 23:7 Comment(1)
I had same problem but it resolved when I added the timezone in php.ini file and installing libapache2-mod-phpx.x and then restarted apache2 server.Bakerman
H
3

The problem was file permissions. I gave the apache2 user read & execute access to usr/share/zoneinfo and etc/localtime. Before, I hadn't set the parents of local time to the right permissions as well. i.e. I only changed the permissions of localtime and zoneinfo without changing the permissions of their parent directories. So stupid! Stepping away from a problem and getting back to it is always useful.

Hindquarter answered 10/1, 2012 at 7:41 Comment(1)
sad panda, all that debugging :/Microtome
M
26

This issue can also occur when using php-fpm in chroot mode, the solution in this case to be to create something like /usr/share/zoneinfo/Europe in your chroot dir then copy your TZ file in to it e.g. London

Marley answered 24/1, 2013 at 16:30 Comment(3)
Awesome, this is exactly what I needed after chrooting my Apache server and only certain PHP scripts were breaking. Turning on error logging I found this was the issue (although I simply copied everything from /usr/share/zoneinfo/* into my chroot jail instead).Alyciaalyda
This happened to me after changing the System TimeZone to something else. My chroot containers had only copied "UTC" into the zoneinfo folder. I copied the whole folder from /usr/share/zoneinfo/* to resolve.Caprification
Thanks, I ran into this and crashed PHP as a result. A bind mount might ensure you stay up to date, like the following: mkdir -p /var/www/siteroot/usr/share/zoneinfo, add /usr/share/zoneinfo /var/www/siteroot/usr/share/zoneinfo none bind,ro,noatime 0 0 to /etc/fstab, then mount /var/www/siteroot/usr/share/zoneinfoRancorous
K
8

Root cause: one of the zoneinfo files could not be opened.

also caused by: too many open files.

I had the same problem today on Ubuntu 14.04.01-LTS "Trusty Tahr", and tried the other answers with no benefit. Permissions were OK, the files were there, the content was as expected.

At last I resolved to run the script from within a command line harness, so that I could try with strace. And this was the result:

openat(AT_FDCWD, "/usr/share/zoneinfo/", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = -1 EMFILE (Too many open files)
open("/usr/share/zoneinfo/zone.tab", O_RDONLY) = -1 EMFILE (Too many open files)
stat("/usr/share/zoneinfo/Europe/Rome", {st_mode=S_IFREG|0644, st_size=2652, ...}) = 0
open("/usr/share/zoneinfo/Europe/Rome", O_RDONLY) = -1 EMFILE (Too many open files)
write(1, "\nFatal error: Unknown: Timezone "..., 104) = 104

What is happening

When PHP "accesses the zoneinfo database" it actually tries to open a directory and some files. If some of these operations fail, the "zoneinfo corrupt" message appears, but it simply means that the PHP process could not open those files:

  • they were not there (chroot jail, zoneinfo install error)
  • they were not there, nor should they be: "Europe/Roem" is not a valid timezone but a typo.
  • they were there, but with wrong permissions.
  • they were there, but the process isn't authorized (SELinux, AppArmor, ...)
  • they were there, but the fopen operation is temporarily not working

My case was the last one: the real problem was that the script was opening too many temporary files, and leaving them open while running. There is a limit on how many files can be opened at the same time, and the zoneinfo file was the proverbial last straw. A quick fix temporarily resolved the problem while I bounced the "too many files" problem to the developer responsible.

Actually I suspect that this also points to PHP continuously opening and closing the zoneinfo database instead of caching it, but it's an investigation for another day.

Intermittent error The "number of open files" thingy is per process, not per PHP script. So there are two (at least) scenarios which could lead to a hard-to-diagnose, possibly intermittent/nonreproducible error:

  • a slow resource leak by some long-running process, e.g. under Racket.
  • a resource hogging by another script or subroutine running in the same process, and possibly not even related to PHP at all.

A PHP script that, right or wrong, allocates 800 files could work okay until it meets another subprocess that has allocated 224 files. The limit of 1024 open files per process is reached and in that case the process fails with a mysterious error (which only refers, cryptically at that, to the very last symptom in a long chain of concurrent causes).

Apache: too many web sites.

Apache running with mod_php5 will cause files accessed by PHP to be opened by the Apache process. But the Apache process also keeps its log files open, and every process has a handle to every log file.

So if you have 200 web sites, each with an independent access_log, say /var/www/somesite/logs/access_log, each process will start with some 210 handles already taken for housekeeping, leaving some 800 free for PHP to use.

This can lead to a situation where the development server (with one site) works, and the production server (with 200 sites installed) does not, if the script needs to allocate 900 temporary files at once.

Dirty diagnostics (on Unix/Linux): glob /proc/self/fd and count() the result. Ugly as sin, but it gives a ballpark figure on how many file descriptors are actually open.

Quick and dirty fix (on Unix/Linux): increase the fdlimit on per-process open files, bringing it to 1024 (of course you need to be root). It's more a matter for Server Fault.

Kasey answered 29/1, 2015 at 12:49 Comment(1)
Indeed this became the case, when I was coding an uploader with chunk and concurrency support.Stagg
H
3

The problem was file permissions. I gave the apache2 user read & execute access to usr/share/zoneinfo and etc/localtime. Before, I hadn't set the parents of local time to the right permissions as well. i.e. I only changed the permissions of localtime and zoneinfo without changing the permissions of their parent directories. So stupid! Stepping away from a problem and getting back to it is always useful.

Hindquarter answered 10/1, 2012 at 7:41 Comment(1)
sad panda, all that debugging :/Microtome
M
2

You mention 'downgrading', did you recently upgrade? In PHP 5.3.x you are forced to set a valid value for date.timezone in your php.ini file.

If you didn't recently upgrade you try resolving the issue by re-installing the tzdata package. I work exclusively with CentOS, so I am not sure what the name of Ubuntu's package manager is, but I'm pretty sure tzdata is standard across distros.

$ -> yum reinstall tzdata # switch 'yum' for Ubuntu package manager
$ -> rm -f /etc/localtime
$ -> ln -sf /usr/share/zoneinfo/UTC /etc/localtime # 'UTC' can be replaced with what you prefer
$ -> date # check to see that it stuck

You may want to restart your httpd after this to ensure timezone info is picked up.

-- Edit

Looks like the culprit is your date_i18n() function, which is always being called, unless calling code specifically passes a 3rd arg of 'false'. I ran your code through some test data with $translate set to false, and worked fine.

function mysql2date( $dateformatstring, $mysqlstring, $translate = true ) {

    $translate = false;
    ...
    if ( $translate )
        return 'date_i18n would have been called';
        //return date_i18n( $dateformatstring, $i );
    ...
}

$testPatterns = array(
    array(
        'dateformatstring'  => 'd.m.y',
        'mysqlstring'       => '2011-10-20 05:35:01'
    ),
    array(
        'dateformatstring'  => 'm',
        'mysqlstring'       => '2011-10-20 05:35:01'
    ),
    array(
        'dateformatstring'  => 'd.m.y',
        'mysqlstring'       => '2011-10-20 05:25:22'
    )
);

foreach ($testPatterns as $testPattern) {

    // Not passing arg to over-ride $translate, forces call to date_i18n()
    var_dump(mysql2date($testPattern['dateformatstring'], $testPattern['mysqlstring']));

    // Forcing $translate to false, makes date() call which works fine
    var_dump(mysql2date($testPattern['dateformatstring'], $testPattern['mysqlstring'], false));
}
Microtome answered 5/1, 2012 at 23:16 Comment(23)
<?php 2 echo date("r"); 3 ?>Hindquarter
sorry I meant to say do you think that I should still reinstall tzdata even thought the php script in my comment above returned the date? Also, I recently performed an apt-get updateHindquarter
I reinstalled tzdata (apt-get install --reinstall tzdata) and it tells me that Local time is now: Thu Jan 5 15:39:24 PST 2012. Universal Time is now: Thu Jan 5 23:39:24 UTC 2012.Hindquarter
@TimnitGebru: That looks good. Try restarting your httpd, and see if your issue is resolved.Microtome
thanks. I restarted apache by performing /etc/init.d/apache2 restartHindquarter
@TimnitGebru: I see you updated your post with code, can you also post a var_dump($mysqlstring), and var_dump($dateformatstring)?Microtome
thanks so much for your help Digital Precision. I'm not quite sure how to proceed because this is not my code. This is code that comes as part of wordpress. It is found in wordpress_root_directory/wp-includes/functions.php. I changed the default setting of $translate=false but that didn't solve the problem. I guess the function calling mysql2date is passing $translate=true. I still don't understand why it is suddenly broken.Hindquarter
@TimnitGebru: Be sure your running the latest version of the software. You may want to check with you hosting provider that they didn't recently make any changes. Also do some search on Wordpress forums for anyone that may be having similar issues.Microtome
@TimnitGebru: You can set $translate = false at the start of the function and override any incoming values, so you are forcing it through php's date() and not the custom function. Updated post to reflect change.Microtome
Hi Digital Precision, I just upgraded to wordpress 3.3.1 and the same problem persists. Also, when I try to update plugins, I get the following error log:Hindquarter
Thanks again for continuing to help me. I run an unmanaged linode server. I upgraded to wordpress 3.3.1 and the same problem persists. For now I have mysql2date just return false and that seems to work but now I can't upgrade the wordpress plugins because I get another date() related error. I have updated my post with an error log and the related code.Hindquarter
@TimnitGebru: I use linode too, good stuff. I wouldn't just return false from mysql2date, I would set translate to false, it may be enough to get your plugin working. Can you do me a favor and do a php -i | fgrep -i date from your shell, and paste the contents in your OP?Microtome
sorry I forgot to add that I set $translate=false and it was still not working. The error is on mysql2date is on line 33 where it says $i = strtotime( $m );I have just updated my OP with the php -i | fgrep -i date output.Hindquarter
What do you get when you do a date via shell?Microtome
Oops sorry I keep on entering my comments before I'm done. Per Fatih Abdullah's suggestion below I ran the command echo date("r") in php earlier and got Thu, 05 Jan 2012 15:20:54Hindquarter
Run it from the shell... I'm curious to see which timezone is set.Microtome
I wrote a script called time.php: #!/usr/bin/php <?php echo date("r"); ?> and did chmod +x time.php and ran ./time.php. Is that what you mean? Then the output I get is Thu, 05 Jan 2012 22:32:15 -0800Hindquarter
Php has you in LA timezone, hence the -0800. Type date in your terminal.Microtome
date in terminal shows Thu Jan 5 22:52:13 PST 2012. I just did a var_dump of struc['lastmodunix'] from line 345-6 of the second snippet of code I posted and stored it in a variable $variable. Executing date('M j',$variable)from the shell then gives me no error and I get the output: Jan 5. Maybe the date() function wordpress is using is somewhere else? I'm really confusedHindquarter
Try rebooting the server. I know, cliche, but I had a time zone prob with my linode boxes too. Maybe a reset after your yz data reinstall will work.Microtome
@TimnitGebru: Did you figure it out?Microtome
no :) I'm back at at it tomorrow. I'll update if I figure it outHindquarter
This helped. Downloaded a Docker container with WordPress from appcontainers.com and had to perform this in order to install and run WP there correctly.Karolyn
C
0

This issue is related to tzdata package. Reinstall it with following command.

sudo apt-get install --reinstall tzdata

Ensure that it is correct with following command

sudo dpkg-reconfigure tzdata

Go to php.ini file and check for date.timezone. If it is still empty, write down your continent/city. Finally, restart the server. Done!

Caliper answered 15/6 at 10:33 Comment(0)
K
-1

I change localtime file for my GMT setting like mv /usr/share/zoneinfo/Asia/Karachi localtime Then followinf error occurs.

date_default_timezone_get(): Timezone database is corrupt - this should never happen!

Solution : Revert you local time setting. Tips : Always keep a backup copy of your old local time so that you can recover any expected OS / Software issue

Kristynkrock answered 30/5, 2018 at 8:2 Comment(0)
D
-2

may be this can help you PHP – Set Timezone

Deficit answered 5/1, 2012 at 23:15 Comment(1)
thanks for that. When I follow the instructions it does show the date: Thu, 05 Jan 2012 15:20:54Hindquarter

© 2022 - 2024 — McMap. All rights reserved.