PHP 时区数据库损坏错误
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8751221/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
PHP Timezone database is corrupt error
提问by Timnit Gebru
I have a wordpress website which suddenly stopped working today. When I look at the logs I see and error:
我有一个 wordpress 网站,今天突然停止工作。当我查看日志时,我看到并出错:
[error] [client 50.78.108.177] PHP Fatal error: strtotime(): Timezone database is corrupt - this should neverhappen!
[错误] [客户50.78.108.177] PHP致命错误:的strtotime():时区数据库已损坏-这应该永远不会发生!
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.
在谷歌上阅读后,有人说他们在/usr/share/zoneinfo 中发现了权限问题。我尝试将权限更改为 777、775、770,但仍然出现相同的错误。我在 Ubuntu 10.04.3 LTS 上运行 php PHP 5.3.2。任何建议或建议都会有所帮助。如果一切都失败了,我将尝试降级到早期版本的 php,但我想在这样做之前尝试其他事情。
thanks, Timnit
谢谢,蒂姆尼特
Update
just in case it helps: the error points to strtotime
in the function below
更新
以防万一它有帮助:错误指向strtotime
下面的函数
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.
更新#2:
现在我通过简单地使用上面的函数return false;
而不执行任何操作来解决这个问题。但是我仍然没有弄清楚问题的根本原因。
update#3:
更新#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"
string(5) "dmy" string(1) "m" string(5) "dmy" string(1) "m" string(5) "dmy" 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"
字符串(19) "2011-10-20 05:35:01" 字符串(19) "2011-10-20 05:35:01" 字符串(19) "2011-10-20 05:25:22" 字符串( 19) "2011-10-20 05:25:22" 字符串(19) "2011-10-19 05:10:06" 字符串(19) "2011-10-19 05:10:06"
update#4:
there is another code snippet that is generating the error log below:
更新#4:
还有另一个代码片段正在生成下面的错误日志:
PHP Fatal error: date(): Timezone database is corrupt - this should neverhappen! 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
PHP 致命错误:date():时区数据库已损坏 - 这绝不应该 发生!在第 346 行的/srv/www/motionthink.com/public_html/wp-admin/includes/class-wp-filesystem-direct.php 中,引用者: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
更新#5:
做php -i | fgrep -i date
退货
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
构建日期 => 2011 年 12 月 13 日 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
然后我编辑了 php.ini 文件,将时区设置为“美国/洛杉矶”并得到了这个输出
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
然后我重新启动了apache2。我仍然收到错误
采纳答案by Timnit Gebru
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.
问题是文件权限。我给了 apache2 用户对 usr/share/zoneinfo 和 etc/localtime 的读取和执行访问权限。之前,我也没有将本地时间的父级设置为正确的权限。即我只更改了 localtime 和 zoneinfo 的权限,而没有更改其父目录的权限。那么蠢!远离问题并回到它总是有用的。
回答by CoderChris
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
在 chroot 模式下使用 php-fpm 时也会出现此问题,在这种情况下的解决方案是在 chroot 目录中创建类似 /usr/share/zoneinfo/Europe 的内容,然后将您的 TZ 文件复制到其中,例如 London
回答by LSerni
Root cause: one of the zoneinfo files could not be opened.
根本原因:无法打开 zoneinfo 文件之一。
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.
我今天在 Ubuntu 14.04.01-LTS“Trusty Tahr”上遇到了同样的问题,并尝试了其他答案但没有任何好处。权限正常,文件在那里,内容符合预期。
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:
最后我决定从命令行工具中运行脚本,以便我可以尝试使用strace
. 这就是结果:
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:
当 PHP “访问 zoneinfo 数据库”时,它实际上会尝试打开一个目录和一些文件。如果其中某些操作失败,则会出现“zoneinfo 损坏”消息,但这仅表示 PHP 进程无法打开这些文件:
- 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
- 他们不在那里(chroot jail,zoneinfo 安装错误)
- 他们不在那里,也不应该在那里:“欧洲/罗马”不是一个有效的时区,而是一个错字。
- 他们在那里,但权限错误。
- 他们在那里,但该过程未经授权(SELinux、AppArmor 等)
- 他们在那里,但
fopen
操作暂时不起作用
My case was the last one: the realproblem 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.
我的情况是最后一个:真正的问题是脚本打开了太多临时文件,并在运行时让它们保持打开状态。可以同时打开多少个文件是有限制的,众所周知,zoneinfo 文件是最后一根稻草。当我将“文件太多”问题退回给负责的开发人员时,快速修复暂时解决了该问题。
Actually I suspect that this alsopoints to PHP continuously opening and closing the zoneinfo database instead of cachingit, but it's an investigation for another day.
实际上我怀疑这也指向 PHP 不断打开和关闭 zoneinfo 数据库而不是缓存它,但这是另一天的调查。
Intermittent errorThe "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:
间歇性错误“打开文件的数量”是每个进程,而不是每个 PHP 脚本。因此,有两种(至少)情况可能导致难以诊断的、可能是间歇性/不可重现的错误:
- 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.
- 某些长时间运行的进程导致缓慢的资源泄漏,例如在 Racket 下。
- 在同一进程中运行的另一个脚本或子程序占用的资源,甚至可能与 PHP 根本无关。
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 casethe process fails with a mysterious error (which only refers, cryptically at that, to the very last symptom in a long chain of concurrent causes).
一个分配了 800 个文件的 PHP 脚本可以正常工作,直到它遇到另一个分配了 224 个文件的子进程。达到了每个进程 1024 个打开文件的限制,在这种情况下,进程失败并出现一个神秘的错误(这只是指一长串并发原因中的最后一个症状)。
Apache: too many web sites.
Apache:网站太多。
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 filesopen, and every process has a handle to every log file.
Apache 运行mod_php5
将导致 PHP 访问的文件被 Apache 进程打开。但是 Apache 进程也保持其日志文件打开,并且每个进程都有每个日志文件的句柄。
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.
因此,如果您有 200 个网站,每个网站都有一个独立的 access_log,比如说/var/www/somesite/logs/access_log
,每个进程将开始使用大约 210 个已经用于内务处理的句柄,剩下大约 800 个可供 PHP 使用。
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.
如果脚本需要一次分配 900 个临时文件,这可能会导致开发服务器(一个站点)工作,而生产服务器(安装了 200 个站点)不工作。
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.
脏诊断(在 Unix/Linux 上):glob
/proc/self/fd
和count()
结果。像罪一样丑陋,但它给出了实际打开了多少文件描述符的大致数字。
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.
快速和肮脏的修复(在 Unix/Linux 上):增加每个进程打开文件的 fdlimit,使其达到 1024(当然你需要是 root)。这更像是Server Fault 的问题。
回答by Mike Purcell
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.
你提到“降级”,你最近升级了吗?在 PHP 5.3.x 中,您被迫date.timezone
在 php.ini 文件中设置有效值。
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.
如果您最近没有升级,请尝试通过重新安装tzdata
软件包来解决问题。我专门使用 CentOS,所以我不确定 Ubuntu 的包管理器的名称是什么,但我很确定它tzdata
是跨发行版的标准。
$ -> 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.
您可能需要在此之后重新启动 httpd 以确保获取时区信息。
-- 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.
看起来罪魁祸首是你的 date_i18n() 函数,它总是被调用,除非调用代码专门传递了“false”的第三个参数。我通过将 $translate 设置为 false 的一些测试数据运行了您的代码,并且运行良好。
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));
}
回答by fatih
may be this can help you PHP – Set Timezone
也许这可以帮助你PHP – 设置时区
回答by Adnan
I change localtime file for my GMT setting like mv /usr/share/zoneinfo/Asia/Karachi localtime Then followinf error occurs.
我更改了我的 GMT 设置的本地时间文件,例如 mv /usr/share/zoneinfo/Asia/Karachi localtime 然后出现 followinf 错误。
date_default_timezone_get(): Timezone database is corrupt - this should neverhappen!
date_default_timezone_get():时区数据库已损坏-这应该永远不会发生!
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
解决方案:恢复本地时间设置。提示:始终保留旧本地时间的备份副本,以便您可以恢复任何预期的操作系统/软件问题