programing

PHP 시간대 데이터베이스가 손상되었습니다. 오류

closeapi 2023. 3. 17. 21:30
반응형

PHP 시간대 데이터베이스가 손상되었습니다. 오류

워드프레스 웹사이트가 오늘 갑자기 작동을 멈췄어요.로그를 보면, 다음의 에러가 표시됩니다.

[오류] [클라이언트 50.78.108.177] PHP 치명적 오류: strtotime(): 타임존 데이터베이스가 파손되었습니다.이러한 일은 일어나지 않습니다.

구글에서 읽은 후, 한 사람이 /usr/share/zoneinfo에서 권한 문제를 발견했다고 말했습니다.777, 775, 770으로 권한을 변경했는데도 계속 같은 오류가 발생합니다.Ubuntu 10.04.3 LTS에서 PHP 5.3.2를 실행하고 있습니다.어떤 제안이나 추천이든지 도움이 될 것입니다.다른 모든 것이 실패하면 이전 버전의 php로 다운그레이드를 시도합니다만, 그 전에 다른 것을 시도해 보고 싶었습니다.

고마워, 팀니트


될 해서: 는 「」를 있습니다.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 );
}

2번:
으로서는 단순히 했습니다.return false;.하지만 저는 아직 문제의 근본 원인을 파악하지 못했습니다.

업데이트 #3:

var_dump($dateformatstring)

string(5) "d.m.y" string(1) "m" string(5) "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-19 05:06" string(19) "2011-10:10:05:06" string(19)

업데이트 #4:
다음 에러 로그를 생성하는 다른 코드 조각이 있습니다.

PHP 치명적 오류: date():타임존 데이터베이스가 손상되었습니다. 346행의 /srv/www/motionthink.com/public_html/wp-admin/includes/class-wp-filesystem-direct.php에서 이러한 일이 발생하지 않아야 합니다.참조자: wp_root_directory/wp-admin/plugins.database?database_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 

5번:
하고 있다php -i | fgrep -i date

제조일 => 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

그런 다음 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를 재시작했습니다.아직 에러가 난다.

이 문제는 chroot 모드에서 php-fpm을 사용하는 경우에도 발생할 수 있습니다.이 경우의 해결책은 chroot dir에 /usr/share/zoneinfo/Europe와 같은 것을 작성한 후 TZ 파일을 복사하는 것입니다.런던

근본 원인: zoneinfo 파일 중 하나를 열지 못했습니다.

또한 원인: 열려 있는 파일이 너무 많습니다.

오늘 Ubuntu 14.04.01-LTS "Trusty Tahr"에서도 같은 문제가 발생하여 다른 답변을 시도했지만 소용이 없었습니다.권한도 괜찮았고, 파일도 있었고, 내용도 예상대로였습니다.

으로 스크립트를 하니스 '을 사용해 .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 time, zoneinfo 설치 오류)
  • "Europe/Roem"은 유효한 타임존이 아니라 오타입니다.
  • 거기 있었는데 잘못된 허가를 받았나 봐요
  • 있었지만 프로세스가 승인되지 않았습니다(SELinux, AppArmor 등).
  • 거기에 있었지만, 그 사람은 있었다.fopen하지 않는다

마지막 케이스입니다.진짜 문제는 스크립트가 너무 많은 임시 파일을 열고 실행 중에 파일을 열어두는 이었습니다.동시에 열 수 있는 파일 수에는 제한이 있으며 zoneinfo 파일은 속설의 마지막 스트로입니다."too many files" 문제를 담당 개발자에게 돌려보냈을 때 빠른 수정으로 일시적으로 문제가 해결되었습니다.

사실 이것 또한 PHP가 zoneinfo 데이터베이스를 캐싱하지 않고 계속 열고 닫는 것을 의미한다고 생각합니다만, 이것은 다른 날의 조사입니다.

간헐적 오류 "열린 파일 수"는 PHP 스크립트가 아닌 프로세스당입니다.따라서 진단하기 어려운 오류, 간헐적 오류 또는 재현 불가능한 오류가 발생할 수 있는 시나리오는 적어도 두 가지가 있습니다.

  • 예를 들어 Racket과 같은 장기 프로세스로 인한 느린 자원 누출.
  • 동일한 프로세스에서 실행 중인 다른 스크립트 또는 서브루틴에 의한 리소스 호깅(PHP와 전혀 관련이 없을 도 있음)

옳든 그르든 800개의 파일을 할당하는 PHP 스크립트는 224개의 파일을 할당한 다른 하위 프로세스를 충족할 때까지 정상적으로 작동합니다.프로세스당 열려 있는 파일이 1024개라는 제한에 도달하면 프로세스가 실패하고 알 수 없는 오류가 발생합니다(암호적으로 이 오류는 긴 동시 원인 체인의 마지막 증상만 참조합니다).

Apache: 웹 사이트가 너무 많습니다.

Apache와 함께 실 。mod_php5PHP에서 액세스하는 파일이 Apache 프로세스에 의해 열립니다.그러나 Apache 프로세스에서는 로그 파일도 열린 상태로 유지하며 모든 프로세스에는 모든 로그 파일에 대한 핸들이 있습니다.

각각 의 웹 가 있는 "access_log"로합니다./var/www/somesite/logs/access_log각 프로세스는 하우스키핑용으로 이미 210개 정도의 핸들로 시작되며, PHP에 800개 정도의 빈 공간이 남아 있습니다.

이로 인해 스크립트가 900개의 임시 파일을 동시에 할당해야 하는 경우 개발 서버(1개의 사이트 포함)는 동작하지만 운영 서버(200개의 사이트가 설치된 상태)는 동작하지 않을 수 있습니다.

지저분한 진단(Unix/Linux): glob /proc/self/fd ★★★★★★★★★★★★★★★★★」count()▶ ▶ 열려 있는 으로 알 수 있습니다.보기 흉하지만 실제로 열려 있는 파일 기술자의 개수는 대략적으로 알 수 있습니다.

빠르고 더러운 수정(Unix/Linux): 프로세스별로 열려 있는 파일의 fdlimit을 증가시켜 1024로 만듭니다(물론 루트여야 합니다).이것은 서버 장애에 관한 문제입니다.

문제는 파일 권한입니다.apache2 사용자에게 usr/share/zoneinfo 등에 대한 읽기 & 실행 액세스 권한을 부여했습니다.이전에는 현지 시간대의 부모에게도 올바른 허가를 주지 않았습니다.부모 디렉토리의 권한을 변경하지 않고 localtime 및 zoneinfo 권한만 변경했습니다.바보같다!문제에서 한 발짝 물러서서 다시 문제점으로 돌아가는 것은 항상 유용합니다.

'하셨는데 다운그레이드'라고 하셨는데 최근에 업그레이드하셨나요?5.에서는, PHP 5.3.x 의 가 있습니다.date.timezone fileini.ini.ini에 해 주세요.

않은 다시 합니다.tzdata★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★OS만을 취급하고 있기 때문에 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를 재시작하여 시간대 정보가 선택되도록 할 수 있습니다.

--편집

발신 코드가 특별히 'false'의 세 번째 arg를 통과하지 않는 한 원인은 항상 호출되는 date_i18n() 함수인 것 같습니다.$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));
}

mv /usr/share/zoneinfo/Asia/Karchi localtime과 같은 GMT 설정의 localtime 파일을 변경하면 followinf 오류가 발생합니다.

date_default_timezone_get():시간대 데이터베이스가 손상되었습니다. 절대 이런 일이 있어서는 안 됩니다!

해결책 : 로컬 시간 설정을 되돌립니다.힌트: 예상되는 OS/소프트웨어 문제를 복구할 수 있도록 항상 이전 현지시간 백업본을 보관합니다.

이것이 PHP타임존을 설정하는 데 도움이 될 수 있습니다.

언급URL : https://stackoverflow.com/questions/8751221/php-timezone-database-is-corrupt-error

반응형