On servers which have not set a timezone in php.ini, installation of Drupal 8 in languages other than English fails as soon as a .po file is loaded because date() is called before the user has set a timezone, and that throws a warning which breaks site installation.

PHP requires that we either call date_default_timezone_set(), or set date.timezone in php.ini. Drupal makes sure to call date_default_timezone_set() from both drupal_session_initialize() and _drupal_bootstrap_page_cache(), using drupal_get_user_timezone() to determine the timezone that's been set for the site during the install process.

PHP < 5.4 will attempt to use the TZ environment variable, or query the operating system, but will throw a warning in either case because these aren't considered reliable ways to determine the timezone. PHP >= 5.4 will not do either, but simply throw a warning.

As a result of all this, PoHeader::__construct()'s call to date() will generate warnings while loading translations between when the user has selected a language and when the user has set the site's timezone.

I see two possible solutions: first, in the __construct() method, use set_error_handler() and restore_error_handler() to try the call to date(), and catch the PHP warning in the case that the timezone hasn't been set yet. If so, call date_default_timezone_set('UTC') before calling date(). (See http://stackoverflow.com/questions/1241728/can-i-try-catch-a-warning for an example of how to do this.)

Second solution: simply call @date() instead of date() in this method to make sure site installation can run correctly. Lots of code in core uses @ to ignore errors, and I think this is another case where it's necessary.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

mvc’s picture

Status: Active » Needs review
FileSize
627 bytes
sfyn’s picture

Issue tags: +i18n, +d8mtl

+1 - I applied this patch and worked great for me.

plach’s picture

Component: language system » locale.module

Moving to the proper queue to ensure the right eyes look at this.

catch’s picture

Status: Needs review » Needs work

For solution 1 see #1247666: Replace @function calls with try/catch ErrorException blocks. I really like that it's possible to do that, but we need to figure it out there first.

Patch here looks reasonable to me just needs comments updating for coding standards.

mvc’s picture

@catch: i'd be happy to tweak the comment format but afaict from https://drupal.org/node/1354 i'm already doing it right. i guess i'm missing something; could you let me know how you'd like me to write that comment?

star-szr’s picture

@mvc - The comment wraps correctly at 80 characters but needs to be a complete sentence (start with a capital letter, end in a period). See https://drupal.org/node/1354#general.

mvc’s picture

Status: Needs work » Needs review
FileSize
635 bytes

thanks for the tip, Cottser.

catch’s picture

Status: Needs review » Reviewed & tested by the community

Looks good now, thanks!

catch’s picture

Status: Reviewed & tested by the community » Needs work

Hmm I just committed this then I realised why don't we just call date_default_timezone_set() here then?

Gábor Hojtsy’s picture

Issue tags: +D8MI

What is d8mtl supposed to signify? There are only two of those issues at http://drupal.org/project/issues/search/drupal?issue_tags=d8mtl. Tagging for D8MI.

mvc’s picture

catch: as i mentioned above, this gets run every time a .po file is loaded, which happens early during site install before we've even asked the user what their timezone is. in fact, this needs to run so that we can ask the user that question in their own language :) once they've answered that question, drupal calls date_default_timezone_set() for us and all's good; it's a temporary problem (but one that breaks site installs for some setups). we could use try/catch to set this temporarily to UTC if no timezone's been set yet once #1247666: Replace @function calls with try/catch ErrorException blocks lands, as you suggested earlier, but for now i don't see an alternative other than to ignore the warning.

gábor: 'd8mtl' was a tag we asked people to use during a D8 code sprint in montreal in january (http://groups.drupal.org/node/272733), which was well attended, although most people didn't bother to use the tag. if that's not how we're supposed to use tags, let me know and i'll remove it from this and the other issue.

catch’s picture

Could we check via ini_get() for a timezone and fall back if it's not set?

Gábor Hojtsy’s picture

@mvc: ah, thanks. That sounded fairly similar to "Drupal 8 multilingual" from "mtl" :D So I wanted to make sure the D8MI tag is used for tracking.

mvc’s picture

ini_get() doesn't help because date_default_timezone_set() does not do the same thing as ini_set('date.timezone', ...); php keeps those separate (see below for a demonstration). we would have to call @date_default_timezone_get(), check $php_errormsg, then set a temporary timezone if there was a warning. that doesn't seem like a big win to me.

mvc@formation:~% php -v
PHP 5.3.21-1~dotdeb.0 with Suhosin-Patch (cli) (built: Jan 27 2013 10:27:28) 
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2013 Zend Technologies
    with Suhosin v0.9.33, Copyright (c) 2007-2012, by SektionEins GmbH
mvc@formation:~% php -a
Interactive shell

php > print date_default_timezone_get();
PHP Warning:  date_default_timezone_get(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/New_York' for 'EST/-5.0/no DST' instead in php shell code on line 1
America/New_York
php > print date('r');
PHP Warning:  date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/New_York' for 'EST/-5.0/no DST' instead in php shell code on line 1
Fri, 22 Feb 2013 11:16:06 -0500
php > $a = ini_get_all();
php > print_r($a['date.timezone']);
Array
(
    [global_value] =>
    [local_value] =>
    [access] => 7
)
php > date_default_timezone_set('America/New_York');
php > print date_default_timezone_get();
America/New_York
php > print date('r');
Fri, 22 Feb 2013 11:16:47 -0500
php > $a = ini_get_all();
php > print_r($a['date.timezone']);
Array
(
    [global_value] =>
    [local_value] =>
    [access] => 7
)
php >
catch’s picture

Status: Needs work » Fixed

Hmm yeah I realised it's not the same as I typed it. It looks like date_default_timezone_get() does less guessing in PHP 5.4, but we don't require that an it still might not be consistent even then, so let's just call this another workaround PHP oddities and leave it fixed.

mvc’s picture

right, it just gives up and throws a warning instead of trying to guess -- that's php for you. anyways, thanks for the commit!

Automatically closed -- issue fixed for 2 weeks with no activity.