База данных часовых поясов PHP является поврежденной ошибкой
У меня есть сайт Wordpress, который внезапно прекратил работать сегодня. Когда я смотрю на журналы, которые вижу и ошибки:
[ошибка] [клиент 50.78.108.177] PHP Неустранимая ошибка: strtotime(): Timezone база данных повреждена - этого никогда не должно быть!
После чтения в Google один человек сказал, что обнаружил проблему с разрешениями в /usr/share/zoneinfo. Я попытался изменить разрешения на 777, 775, 770, и я все равно продолжаю получать ту же ошибку. Я запускаю php PHP 5.3.2 на Ubuntu 10.04.3 LTS. Любые предложения или рекомендации будут полезны. Если все остальное не работает, я собираюсь попытаться понизить до более ранней версии php, но я хотел попробовать другие вещи, прежде чем делать это.
спасибо,
Timnit
Обновление
на всякий случай это помогает: ошибка указывает на 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:
на данный момент я исправил проблему, просто используя функцию выше return false;
, ничего не выполняя. Однако я до сих пор не понял причину проблемы.
обновление # 3:
var_dump($dateformatstring)
string (5) строка "d.m.y" (1) строка "m" (5) строка "d.m.y" (1) "m" строка (5) строка "d.m.y" (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"
Обновление # 4:
есть еще один фрагмент кода, который генерирует журнал ошибок ниже:
PHP Неустранимая ошибка: дата(): база данных часовых поясов повреждена - это должно никогда не случится! в /srv/www/motionthink.com/public_html/wp-admin/includes/class-wp-filesystem-direct.php в строке строка 346,: wp_root_directory/WP-администратора/plugins.php? plugin_status = обновление
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:
выполнение php -i | fgrep -i date
возвращает
Дата сборки = > 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
то я отредактировал файл php.ini, чтобы установить часовой пояс в "America/Los Angeles" и получил этот вывод
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
Затем я перезапустил apache2. Я все еще получаю сообщение об ошибке
Ответы
Ответ 1
Проблема заключалась в разрешении файла. Я дал пользователю apache2 прочитать и выполнить доступ к usr/share/zoneinfo и т.д. /Localtime. Раньше я не устанавливал родителей локального времени на правильные разрешения. т.е. я только изменил разрешения localtime и zoneinfo без изменения разрешений их родительских каталогов. Так глупо! Уйти от проблемы и вернуться к ней всегда полезно.
Ответ 2
Эта проблема также может возникать при использовании php-fpm в режиме chroot, решением в этом случае должно быть создание чего-то вроде /usr/share/zoneinfo/Europe в вашем каталоге chroot, а затем скопировать ваш TZ файл в него, например. Лондон
Ответ 3
Корневая причина: один из файлов zoneinfo не может быть открыт.
также вызвано: слишком много открытых файлов.
У меня была такая же проблема сегодня на Ubuntu 14.04.01-LTS "Trusty Tahr", и попробовал другие ответы без каких-либо преимуществ. Разрешения были в порядке, файлы были там, содержимое было как ожидалось.
Наконец-то я решил запустить script из жгута командной строки, чтобы я мог попробовать с 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
Что происходит
Когда PHP "обращается к базе данных zoneinfo", он фактически пытается открыть каталог и некоторые файлы. Если некоторые из этих операций не работают, появляется сообщение "zoneinfo corrupt", но это просто означает, что процесс PHP не смог открыть эти файлы:
- их там не было (chroot jail, ошибка установки zoneinfo)
- их там не было, и они не должны быть: "Европа/Roem" не является допустимым часовым поясом, а опечаткой.
- они были там, но с неправильными разрешениями.
- они были там, но процесс не разрешен (SELinux, AppArmor,...)
- они были там, но операция
fopen
временно не работает
Мой случай был последним: проблема реальная заключалась в том, что script открывал слишком много временных файлов и оставлял их открытыми во время работы. Существует ограничение на то, сколько файлов можно открыть одновременно, а файл zoneinfo - это пресловутая последняя солома. Быстрое исправление временно разрешило проблему, в то время как я отбросил проблему "слишком много файлов" ответственному разработчику.
На самом деле я подозреваю, что это также указывает на то, что PHP постоянно открывает и закрывает базу данных zoneinfo, а не кэширует ее, но это расследование на другой день.
Прерывистая ошибка
"Количество открытых файлов" доступно для каждого процесса, а не для PHP script. Таким образом, существует два (по крайней мере) сценария, которые могут привести к жесткой диагностике, возможно прерывистой/невоспроизводимой ошибке:
- медленная утечка ресурсов в результате какого-то длительного процесса, например. под Racket.
- привязка ресурсов другим script или подпрограммой, выполняющейся в том же процессе, и, возможно, даже не связанной с PHP.
PHP скрипт, который, правильно или неправильно, выделяет 800 файлов, может работать нормально, пока не встретится с другим подпроцессом, который выделил 224 файла. Достигнуто ограничение на 1024 открытых файла на процесс, и в этом случае процесс завершится с таинственной ошибкой (которая относится только к ней с критической точки зрения к самому последнему симптому в длинной цепочке одновременных причин).
Apache: слишком много веб-сайтов.
Apache, работающий с mod_php5
, заставит файлы, к которым обращается PHP, будет открыт процессом Apache. Но процесс Apache также сохраняет свои файлы журналов открытыми, и каждый процесс имеет дескриптор для каждого файла журнала.
Итак, если у вас есть 200 веб-сайтов, каждый из которых имеет независимый access_log, скажем /var/www/somesite/logs/access_log
, каждый процесс начнется с 210 дескрипторов, уже принятых для домашнего хозяйства, оставив около 800 бесплатных для PHP.
Это может привести к ситуации, когда сервер разработки (с одним сайтом) работает, а производственный сервер (с 200 установленными сайтами) не работает, если script необходимо одновременно выделить 900 временных файлов.
Грязная диагностика (в Unix/Linux): glob
/proc/self/fd
и count()
результат. Уродливый как грех, но он дает приблизительную цифру о том, сколько файловых дескрипторов действительно открыто.
Быстрое и грязное исправление (в Unix/Linux): увеличьте fdlimit для открытых файлов в каждом процессе, доведя его до 1024 (конечно, вам нужно быть root). Это более важно для Ошибка сервера.
Ответ 4
Вы упоминаете "понижение", недавно вы обновили? В PHP 5.3.x вы вынуждены установить допустимое значение для date.timezone
в файле php.ini.
Если вы не обновили обновление, попробуйте решить проблему, переустановив пакет 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
Вы можете перезапустить свой httpd после этого, чтобы получить информацию о часовом поясе.
- Изменить
Похоже, что виновником является ваша функция date_i18n(), которая всегда вызывается, если только вызывающий код не передает третий аргумент "false". Я проверил ваш код через некоторые тестовые данные с $translate set to 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));
}
Ответ 5
может быть, это может помочь вам PHP - Установить часовую зону
Ответ 6
Я изменяю файл локального времени для своей настройки GMT, например, mv/usr/share/zoneinfo/Asia/Karachi localtime. Затем происходит ошибка followinf.
date_default_timezone_get(): База данных часовых поясов повреждена - этого никогда не должно случиться!
Решение: Отменить настройки локального времени. Советы: Всегда сохраняйте резервную копию вашего старого локального времени, чтобы вы могли исправить любую ожидаемую проблему ОС/программного обеспечения
Ответ 7
У меня похожая проблема
Неустранимая ошибка: mysqli_real_connect(): база данных часовых поясов повреждена - этого никогда не должно случиться! в /var/www/html/wp-includes/wp-db.php в строке 1531
Кто-нибудь может помочь?